How to fill with a different color an area in seaborn.distplot

Is it possible to fill with a color the area outside the two threshold lines (line1 and line2) and limited in Y-axis by the KDE curve drawn by distplot ?(that represents 3-sigmas for my application)

import pylab as pl
import seaborn as sns
#plotting the two lines
p1 = pl.axvline(x=line1,color='#EF9A9A')
p2 = pl.axvline(x=line2,color='#EF9A9A')
#plotting the PDF
sns.distplot(stat, hist=True,color='#388E3C')

result figure

1 answer

  • answered 2017-10-11 10:25 ImportanceOfBeingErnest

    You may use fill_between to fill the area underneath a curve. To get access to the KDE curve from the seaborn plot, you can draw that one first, such that ax.lines only has a single element, which is the curve of interest. Its data is obtained via kde_x, kde_y = ax.lines[0].get_data().

    Then using ax.fill_between() allows to fill the area under the curve. To restrict this to be outside some given data range, the where keyword argument may be used (and interpolate=True should be set to have the area go up to the points in question).

    ax.fill_between(kde_x, kde_y, where=(kde_x<x0) | (kde_x>x1) , 
                    interpolate=True, color='#EF9A9A')
    

    Full example:

    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    stat=np.random.randn(100)
    x0 = -1
    x1 = 1
    
    #plotting the PDF (do this before plotting anything else)
    ax = sns.distplot(stat, hist=True,color='#388E3C')
    kde_x, kde_y = ax.lines[0].get_data()
    
    #plotting the two lines
    p1 = plt.axvline(x=x0,color='#EF9A9A')
    p2 = plt.axvline(x=x1,color='#EF9A9A')
    
    
    ax.fill_between(kde_x, kde_y, where=(kde_x<x0) | (kde_x>x1) , 
                    interpolate=True, color='#EF9A9A')
    
    plt.show()
    

    Image produced by the above code


    Old answer to initial question:

    You may use an axvspan, starting at the left x limit and going to the position of the first line and another one starting at the position of the second line and going to the right x limit.

    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    stat=np.random.randn(100)
    x0 = -1
    x1 = 1
    
    #plotting the two lines
    p1 = plt.axvline(x=x0,color='#EF9A9A')
    p2 = plt.axvline(x=x1,color='#EF9A9A')
    
    #plotting the PDF
    ax = sns.distplot(stat, hist=True,color='#388E3C')
    
    xlim = ax.get_xlim()
    ax.axvspan(xlim[0], x0, color='#EF9A9A', alpha=0.5)
    ax.axvspan(x1, xlim[1], color='#EF9A9A', alpha=0.5)
    #reset xlim
    ax.set_xlim(xlim)
    plt.show()
    

    Image produced by the above code

    Here, we need to adjust the xlimits after setting spans; the reason is that with the spans in place the autoscaling would add another 5% padding to both ends of the axes, resulting in white space. Alternatively you could use zero margin for the xaxis, ax.margins(x=0).