简体   繁体   中英

Can't display the seaborn distplot

I am trying to make a histogram and a density plot using the seaborn module of Python , and on the plot I am also trying to draw a vertical line at the mode. However, the resulting plot does not display any histogram and/or density curve. My code is below:

# a function to compute mode of the histograms shown in Figures `2` and `3` in the paper.
def compute_mode(layer_list):
    
    ax = sns.distplot(layer_list, hist=False, kde=True, kde_kws={'linewidth': 2})
    x = ax.lines[0].get_xdata()
    y = ax.lines[0].get_ydata()
    mode_idx = y.argmax()
    mode_x = x[mode_idx]
    plt.close()
        
    return mode_x

# function to plot the histogram of the layer lists.
def make_density(layer_list, color):

    
    # Plot formatting
    plt.xlabel('Median Stn. MC-Loss')
    plt.ylabel('Density')

    
    # Draw the histogram and fit a density plot.
    sns.distplot(layer_list, hist = True, kde = True,
                 kde_kws = {'linewidth': 2}, color=color)
    
    # compute mode of the histogram.
    mode_x = compute_mode(layer_list)
    
    # draw a vertical line at the mode of the histogram.
    plt.axvline(mode_x, color='blue', linestyle='dashed', linewidth=1.5)
    plt.text(mode_x, 0.16, 'mode: {:.4f}'.format(mode_x))

layer_list = [ 1.0,2.0,3.0,4.0,2.0,3.0,1.0,6.0,10.0,2.0]
make_density(layer_list, 'green')

在此处输入图片说明 I think the problem arises from the line plt.axvline(mode_x, color='blue', linestyle='dashed', linewidth=1.5) and plt.text(mode_x, 0.16, 'mode: {:.4f}'.format(mode_x)) .

What am I doing wrong here?

Thank you,

The main problem is that in compute_mode() plt.close() is called, which closes the plot that was just before created in make_density() . Note that sns.distplot is mainly a drawing function which shouldn't be used just for calculations. As the kde was already plotted in make_density() , ax.lines[0] can be passed to compue_mode() to extract the curve data without the need for creating the plot a second time.

Some other remarks:

  • In seaborn 0.11, distplot has be deprecated, and is replaced by two functions: histplot which creates a histogram, optionally with a kde. And displot (without "T") which creates a grid of histogram/kdeplots. Apart from the name confusion, the kde_kws parameter of distplot is called line_kws in histplot , while kde_kws in histplot is meant for the function that calculates the KDE. Also, the kde curve always uses the same color as the histogram.
  • Seaborn's "axes level" functions return an ax that can be used for additional formatting. In your original code you added some labels before calling distplot , but as distplot also might change settings, it is safer to do all these formatting calls afterwards.
  • You might want to read about the object-oriented interface and the difference between ax.set_xlabel() and plt.xlabel() .
import matplotlib.pyplot as plt
import seaborn as sns

# a function to compute mode of the histograms shown in Figures `2` and `3` in the paper.
def compute_mode(line_object):
    x = line_object.get_xdata()
    y = line_object.get_ydata()
    mode_idx = y.argmax()
    return x[mode_idx], y[mode_idx]

# function to plot the histogram of the layer lists.
def make_density(layer_list, color):
    # Draw the histogram and fit a density plot.
    ax = sns.histplot(layer_list, kde=True,
                      line_kws={'linewidth': 2}, color=color)
    # compute mode of the histogram.
    mode_x, mode_y = compute_mode(ax.lines[0])

    # draw a vertical line at the mode of the histogram.
    ax.axvline(mode_x, color='blue', linestyle='dashed', linewidth=1.5)
    ax.text(mode_x, mode_y, 'mode: {:.4f}'.format(mode_x))
    # Plot formatting
    ax.set_xlabel('Median Stn. MC-Loss')
    ax.set_ylabel('Density')

layer_list = [1.0, 2.0, 3.0, 4.0, 2.0, 3.0, 1.0, 6.0, 10.0, 2.0]

make_density(layer_list, 'green')
plt.show()

示例图

Calling seaborn's distplot in compute_mode without specifying the ax messed with the plot. You can simply replace compute_mode by this code:

def compute_mode(layer_list):
    dummy_fig, dummy_ax = plt.subplots()
    ax = sns.distplot(layer_list, hist=False, kde=True, kde_kws={'linewidth': 2}, ax=dummy_ax)
    x = ax.lines[0].get_xdata()
    y = ax.lines[0].get_ydata()
    mode_idx = y.argmax()
    mode_x = x[mode_idx]
    plt.close()

    return mode_x

Even if this workaround works, consider to compute the mode with dedicated tools like scipy's gaussian_kde . It will prevent you from messing with graphical libraries to do math stuff.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM