seaborn kdeplot error: "No contour levels were found within the data range"

Viewed 1437

I am using the seaborn PairGrid function. I have two datasets that I have been trying to plot on the same PairGrid. My diagonals are normalised plt.hists, my lower diagonals are sns.scatterplot and my upper diagonal is sns.kdeplot. However, some of the kdeplots are producing this user warning:

/home/user_xyz/.local/lib/python3.6/site-packages/seaborn/distributions.py:1184: UserWarning: No contour levels were found within the data range.

  • This is what my PairGrid looks like with the error - as you can see for some of the kdeplots the red data is missing and this is what is throwing the warning: plot with error
  • However, interestingly enough, when I plot the red data (which is the missing one) separately, the kdeplots work out just fine! There is no warning. This is what it looks like individually: red data PairGrid
  • Some other things I have noticed are: increasing bw_adjust makes the issue worse and decreasing the bw_adjust removes the issue but instead of getting a proper looking contour plot for my red data I get many tiny circles instead

I thought this might be due to the fact that the distributions are not peaked and are therefore not Gaussian like but that still doesn't explain why separately the red data plots fine or why the blue data plots fine on the PairGrid despite having the same flat distribution as the red data.

Does anyone know why I am unable to properly plot the kdeplots for both datasets on the same PairGrid? Or why this error is occurring?

Thanks!

EDIT:

I've added the code I use down below and have included some toy data that closely resembles the real data (the real data is private). It is in the form of a Google sheet (access should be given) which can then be read in using Pandas. Sorry if this is inconvenient - I have a very large dataset and it isn't stored in a database.

Code:

# data variable contains data inside the linked Google sheet
g = sns.PairGrid(data, hue = "Type")

plt.figure()
g.map_diag(plt.hist, alpha = 0.7, density = True, histtype = 'step', range = [-1.05, 1.05], bins = 20, linewidth = 2)
g.map_upper(sns.kdeplot, hue_order = ['Ch', 'Si'])
g.map_lower(sns.scatterplot, hue_order = ['Ch', 'Si'])
g.add_legend()

for i in range(5):
    for j in range(5):
        g.axes[i, j].set_ylim(-1.1, 1.15)
        
for i in range(5):
    g.axes[i, 0].set_xlim(-0.1, 1.0)
    
for i in range(5):
    g.axes[i, 1].set_xlim(0.5, 1.0)
    
for i in range(5):
    g.axes[i, 2].set_xlim(-0.2, 1.1)
    
for i in range(5):
    g.axes[i, 3].set_xlim(-0.2, 1.2)
    
for i in range(5):
    g.axes[i, 4].set_xlim(-1.2, 1.3)

plt.show()

Data:

https://docs.google.com/spreadsheets/d/1KtX8nZU8ghe55xIEfE5e-srhWqWb5ZPS4G02gRVT-o8/edit?usp=sharing

1 Answers

sns.kdeplot has an option common_norm= which defaults to True. That reduces the two sets relative to their number of elements. As one set is much smaller than the other, it gets so small that it won't be drawn together with the other.

Both sets can be shown at "full" size using g.map_upper(sns.kdeplot, hue_order=['Ch', 'Si'], common_norm=False). Alternatively you can set a lower threshold: g.map_upper(sns.kdeplot, hue_order=['Ch', 'Si'], thresh=0.02).

Note that common_norm=False makes the kdeplot with separated hues more similar to the kdeplot without using hue.

Here is a comparison between the different options for kdeplot, using toy data with a similar difference in set sizes:

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np

M = 30
N1 = 50
N2 = 2
data = pd.DataFrame({'Variable4': np.concatenate([np.random.randn(M, N1).cumsum(axis=0).ravel() / 2 + 10,
                                                  np.random.randn(M, N2).cumsum(axis=0).ravel() + 20]),
                     'Variable5': np.concatenate([np.random.randn(M, N1).cumsum(axis=0).ravel() / 2 + 20,
                                                  np.random.randn(M, N2).cumsum(axis=0).ravel() + 10]),
                     'Type': np.repeat(['Ch', 'Si'], [M * N1, M * N2])})

fig, (ax1, ax2, ax3, ax4) = plt.subplots(ncols=4, figsize=(18, 4))
sns.kdeplot(data=data, x='Variable4', y='Variable5', ax=ax1)
ax1.set_title('Not using hue')
sns.kdeplot(data=data, x='Variable4', y='Variable5', hue='Type', ax=ax2)
ax2.set_title('Default with hue')
sns.kdeplot(data=data, x='Variable4', y='Variable5', hue='Type', common_norm=False, ax=ax3)
ax3.set_title('hue, common_norm=False')
sns.kdeplot(data=data, x='Variable4', y='Variable5', hue='Type', thresh=0.02, ax=ax4)
ax4.set_title('hue, thresh=0.02')
plt.tight_layout()
plt.show()

comparison plot

Related