hachiko
hachiko

Reputation: 747

Seaborn different line color and fill color in density plot

I'm trying to create a density plot in python using Seaborn. I would like the density plot to have one fill color that is different from the line color. Here is an example of what I am trying to create:

enter image description here

And here is the dataframe that I am using:

mtcars = pd.DataFrame.from_dict({'Unnamed: 0': {0: 'Mazda RX4', 1: 'Mazda RX4 Wag', 2: 'Datsun 710', 3: 'Hornet 4 Drive', 4: 'Hornet Sportabout', 5: 'Valiant', 6: 'Duster 360', 7: 'Merc 240D', 8: 'Merc 230', 9: 'Merc 280', 10: 'Merc 280C', 11: 'Merc 450SE', 12: 'Merc 450SL', 13: 'Merc 450SLC', 14: 'Cadillac Fleetwood', 15: 'Lincoln Continental', 16: 'Chrysler Imperial', 17: 'Fiat 128', 18: 'Honda Civic', 19: 'Toyota Corolla', 20: 'Toyota Corona', 21: 'Dodge Challenger', 22: 'AMC Javelin', 23: 'Camaro Z28', 24: 'Pontiac Firebird', 25: 'Fiat X1-9', 26: 'Porsche 914-2', 27: 'Lotus Europa', 28: 'Ford Pantera L', 29: 'Ferrari Dino', 30: 'Maserati Bora', 31: 'Volvo 142E'}, 'mpg': {0: 21.0, 1: 21.0, 2: 22.8, 3: 21.4, 4: 18.7, 5: 18.1, 6: 14.3, 7: 24.4, 8: 22.8, 9: 19.2, 10: 17.8, 11: 16.4, 12: 17.3, 13: 15.2, 14: 10.4, 15: 10.4, 16: 14.7, 17: 32.4, 18: 30.4, 19: 33.9, 20: 21.5, 21: 15.5, 22: 15.2, 23: 13.3, 24: 19.2, 25: 27.3, 26: 26.0, 27: 30.4, 28: 15.8, 29: 19.7, 30: 15.0, 31: 21.4}, 'cyl': {0: 6, 1: 6, 2: 4, 3: 6, 4: 8, 5: 6, 6: 8, 7: 4, 8: 4, 9: 6, 10: 6, 11: 8, 12: 8, 13: 8, 14: 8, 15: 8, 16: 8, 17: 4, 18: 4, 19: 4, 20: 4, 21: 8, 22: 8, 23: 8, 24: 8, 25: 4, 26: 4, 27: 4, 28: 8, 29: 6, 30: 8, 31: 4}, 'disp': {0: 160.0, 1: 160.0, 2: 108.0, 3: 258.0, 4: 360.0, 5: 225.0, 6: 360.0, 7: 146.7, 8: 140.8, 9: 167.6, 10: 167.6, 11: 275.8, 12: 275.8, 13: 275.8, 14: 472.0, 15: 460.0, 16: 440.0, 17: 78.7, 18: 75.7, 19: 71.1, 20: 120.1, 21: 318.0, 22: 304.0, 23: 350.0, 24: 400.0, 25: 79.0, 26: 120.3, 27: 95.1, 28: 351.0, 29: 145.0, 30: 301.0, 31: 121.0}, 'hp': {0: 110, 1: 110, 2: 93, 3: 110, 4: 175, 5: 105, 6: 245, 7: 62, 8: 95, 9: 123, 10: 123, 11: 180, 12: 180, 13: 180, 14: 205, 15: 215, 16: 230, 17: 66, 18: 52, 19: 65, 20: 97, 21: 150, 22: 150, 23: 245, 24: 175, 25: 66, 26: 91, 27: 113, 28: 264, 29: 175, 30: 335, 31: 109}, 'drat': {0: 3.9, 1: 3.9, 2: 3.85, 3: 3.08, 4: 3.15, 5: 2.76, 6: 3.21, 7: 3.69, 8: 3.92, 9: 3.92, 10: 3.92, 11: 3.07, 12: 3.07, 13: 3.07, 14: 2.93, 15: 3.0, 16: 3.23, 17: 4.08, 18: 4.93, 19: 4.22, 20: 3.7, 21: 2.76, 22: 3.15, 23: 3.73, 24: 3.08, 25: 4.08, 26: 4.43, 27: 3.77, 28: 4.22, 29: 3.62, 30: 3.54, 31: 4.11}, 'wt': {0: 2.62, 1: 2.875, 2: 2.32, 3: 3.215, 4: 3.44, 5: 3.46, 6: 3.57, 7: 3.19, 8: 3.15, 9: 3.44, 10: 3.44, 11: 4.07, 12: 3.73, 13: 3.78, 14: 5.25, 15: 5.424, 16: 5.345, 17: 2.2, 18: 1.615, 19: 1.835, 20: 2.465, 21: 3.52, 22: 3.435, 23: 3.84, 24: 3.845, 25: 1.935, 26: 2.14, 27: 1.513, 28: 3.17, 29: 2.77, 30: 3.57, 31: 2.78}, 'qsec': {0: 16.46, 1: 17.02, 2: 18.61, 3: 19.44, 4: 17.02, 5: 20.22, 6: 15.84, 7: 20.0, 8: 22.9, 9: 18.3, 10: 18.9, 11: 17.4, 12: 17.6, 13: 18.0, 14: 17.98, 15: 17.82, 16: 17.42, 17: 19.47, 18: 18.52, 19: 19.9, 20: 20.01, 21: 16.87, 22: 17.3, 23: 15.41, 24: 17.05, 25: 18.9, 26: 16.7, 27: 16.9, 28: 14.5, 29: 15.5, 30: 14.6, 31: 18.6}, 'vs': {0: 0, 1: 0, 2: 1, 3: 1, 4: 0, 5: 1, 6: 0, 7: 1, 8: 1, 9: 1, 10: 1, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 1, 18: 1, 19: 1, 20: 1, 21: 0, 22: 0, 23: 0, 24: 0, 25: 1, 26: 0, 27: 1, 28: 0, 29: 0, 30: 0, 31: 1}, 'am': {0: 1, 1: 1, 2: 1, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 0, 17: 1, 18: 1, 19: 1, 20: 0, 21: 0, 22: 0, 23: 0, 24: 0, 25: 1, 26: 1, 27: 1}}
)

As a first step, I created a density plot with a black color and that worked well.

plt.close()
plt.cla()
plt.clf()

seaborn.displot(mtcars, x="mpg", kind="kde", color = 'black', alpha=.5)
plt.suptitle("Mtcars", x=0.149, y=0.96, ha='left', fontweight = 'bold')
plt.title("density plot", loc = 'left')
plt.xlabel("mpg")
plt.ylabel("density")
plt.tight_layout()
plt.show()

enter image description here

Then I wanted to see if I could make that line color a fill color. So I changed color to fill. But this gave me weird behavior because the fill argument seemed to work but the color was wrong.

plt.close()
plt.cla()
plt.clf()

seaborn.displot(mtcars, x="mpg", kind="kde", fill = 'black', alpha=.5)
plt.suptitle("Mtcars", x=0.125, y=0.97, ha='left', fontweight = 'bold')
plt.title("density plot", loc = 'left')
plt.xlabel("mpg")
plt.ylabel("density")
plt.tight_layout()
plt.show()

enter image description here

When I try both the color and fill arguments at the same time I get this:

plt.close()
plt.cla()
plt.clf()

seaborn.displot(mtcars, x="mpg", kind="kde", color = 'black', fill = '#ffe6b7', alpha=.5)
plt.suptitle("Mtcars", x=0.125, y=0.97, ha='left', fontweight = 'bold')
plt.title("density plot", loc = 'left')
plt.xlabel("mpg")
plt.ylabel("density")
plt.tight_layout()
plt.show()

enter image description here

When I looked again at the documentation for how to use seaborn at this link: https://seaborn.pydata.org/generated/seaborn.kdeplot.html And also by typing in ?seaborn.displot in my console, I see references to hue instead of fill. But hue seems to want a vector that is a variable in the dataframe.

I tried using the hue argument anyway and I got a blank plot.

Does anyone know how to add a line color and a fill color to a density plot that are both colors, not variables in dataframe?

enter image description here

plt.close()
plt.cla()
plt.clf()

seaborn.displot(mtcars, x="mpg", kind="kde", color = 'black', hue = '#ffe6b7', alpha=.5)
plt.suptitle("Mtcars", x=0.125, y=0.97, ha='left', fontweight = 'bold')
plt.title("density plot", loc = 'left')
plt.xlabel("mpg")
plt.ylabel("density")
plt.xlabel("X-Axis")
plt.ylabel("Y-Axis")
plt.tight_layout()
plt.show()

?seaborn.displot

Upvotes: 1

Views: 2094

Answers (2)

JohanC
JohanC

Reputation: 80329

When no hue= is chosen, you can set the fill color via color= and its transparency via alpha=. The line color can be set via ec= (or edgecolor=) and its thickness via lw= (or linewidth=).

Note that sns.displot(kind='kde', ...) calls sns.kdeplot under the hood. sns.displot is the "figure-level" equivalent, creating a new figure, with one or more subplots (depending on col= and row=). The parameters of displot that don't refer to the FacetGrid are sent to kdeplot.

import seaborn as sns

mpg = sns.load_dataset('mpg')
sns.set()
sns.displot(data=mpg['mpg'], fill=True, color='NavajoWhite', alpha=0.8, kind='kde', ec='Navy', lw=2,
            height=4, aspect=3)

sns.displot changing line color

Upvotes: 5

Triet Doan
Triet Doan

Reputation: 12085

But this gave me weird behavior because the fill argument seemed to work but the color was wrong.

This is because fill accepts a boolean. If you set it to True, then seaborn will fill the plot with the color defined in color.

Although I couldn't find a proper way to achieve what you want, a quick solution is to plot it twice, once with fill and one without. So, if you do it like this,

sns.kdeplot(data=mtcars, x='mpg', color='black')
sns.kdeplot(data=mtcars, x='mpg', alpha=.3, fill=True, color='yellow')

then you get what you want.

plot

Upvotes: 0

Related Questions