0

I am wanting to overlay different 2D density plots over each other using the kdeplot() function from seaborn, however the color of the contours aren't appearing in the legend. How would I be able to update the legend with the color?

Code example:

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
sns.kdeplot(x = np.random.random(30), y = np.random.random(30), label = "dist1", ax=ax)
sns.kdeplot(x = np.random.random(30) + 1, y = np.random.random(30) + 1, label = "dist2", ax=ax)
ax.legend()
plt.show()

Output plot

I'm using seaborn v0.12.0

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Vecko
  • 21
  • 1

2 Answers2

2

Found a way to work around the issue. By extracting the colour in the colourcycle, you can manually set the colour of kdeplot() as well as construct the handles for the legend.

import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.lines as mlines

fig, ax = plt.subplots()
handles = []
# Extracting next colour in cycle
color = next(ax._get_lines.prop_cycler)["color"]
sns.kdeplot(x = np.random.random(30), y = np.random.random(30), color = color, label = "dist1", ax=ax)
handles.append(mlines.Line2D([], [], color=color, label="dist1"))

color = next(ax._get_lines.prop_cycler)["color"]
sns.kdeplot(x = np.random.random(30) + 1, y = np.random.random(30) + 1, color = color, label = "dist2", ax=ax)
handles.append(mlines.Line2D([], [], color=color, label="dist1"))


ax.legend(handles = handles)

Output plot

Vecko
  • 21
  • 1
2
  • It's easier create a pandas.DataFrame with a label column, and let the plot API manage the legend handles and labels. In addition to making plotting easier, it's easier to perform additional analysis on the data in a dataframe.
  • Tested in python 3.10, pandas 1.4.3, matplotlib 3.5.2, seaborn 0.12.0

Create a DataFrame

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

np.random.seed(2022)  # for the same sample data each time

# list of dataframes; create each dataframe and use assign to add a label column
df_list = [pd.DataFrame({'x': np.random.random(30),
                         'y': np.random.random(30)}).assign(label='d1'),
           pd.DataFrame({'x': np.random.random(30) + 1,
                         'y': np.random.random(30) + 1}).assign(label='d2')]

# combine the list of dataframes with concat
df = pd.concat(df_list, ignore_index=True)

# display(df.head())
          x         y label
0  0.009359  0.564672    d1
1  0.499058  0.349429    d1
2  0.113384  0.975909    d1
3  0.049974  0.037820    d1
4  0.685408  0.794270    d1

# display(df.tail())
           x         y label
55  1.829995  1.251087    d2
56  1.626445  1.241247    d2
57  1.871438  1.841468    d2
58  1.625907  1.020932    d2
59  1.130638  1.894918    d2

sns.displot

# plot the dataframe in a figure level plot
g = sns.displot(kind='kde', data=df, x='x', y='y', hue='label')

enter image description here

sns.kdeplot

# plot the dataframe in an axes level plot
fig, ax = plt.subplots(figsize=(7, 5))
sns.kdeplot(data=df, x='x', y='y', hue='label', ax=ax)

enter image description here

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158