Fill facecolor in convex hulls for custom seaborn mapping function
Question:
I’m trying to overlay shaded convex hulls to the different groups in a scatter seaborn.relplot
using Matplotlib. Based on this question and the Seaborn example, I’ve been able to successfully overlay the convex hulls for each sex
in the penguins dataset.
# Import libraries
import pandas as pd
import numpy as np
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
data = sns.load_dataset("penguins")
xcol = 'bill_length_mm'
ycol = 'bill_depth_mm'
g = sns.relplot(data = data, x=xcol, y = ycol,
hue = "sex", style = "sex",
col = 'species', palette="Paired",
kind = 'scatter')
def overlay_cv_hull_dataframe(x, y, color, **kwargs):
data = kwargs.pop('data')
# Get the Convex Hull for each group based on hue
for _, group in data.groupby('hue'):
points = group[['x', 'y']].values
hull = ConvexHull(points)
for simplex in hull.simplices:
plt.fill(points[simplex, 0], points[simplex, 1],
facecolor = color, alpha=0.5,
edgecolor = color)
# Overlay convex hulls
g.map_dataframe(overlay_cv_hull_dataframe, x=xcol, y=ycol,
hue='sex')
g.set_axis_labels(xcol, ycol)
However, the convex hulls are not filled in with the same color as the edge, even though I specified that
plt.fill(points[simplex, 0], points[simplex, 1],
facecolor = color, alpha=0.5,
edgecolor = color, # color is an RGB tuple like (0.12, 0.46, 0.71)
)
I’ve also tried setting facecolor='lightsalmon'
like this example and removing the alpha
parameter, but get the same plot. I think I’m really close but I’m not sure what else to try.
How can I get the convex hulls to be filled with the same color
as edgecolor
and the points?
Answers:
(Your code seems to have some typos, writing 'x'
, 'y'
and 'hue'
instead of x
, y
and hue
).
simplex
contains the indices of the coordinates of one edge of the convex hull. To fill a polygon, you need all edges, or hull.vertices
.
g.map_dataframe
only calls the function once per subplot. As such, color
is only usable if you wouldn’t be using hue
. Instead, you’ll need to store the individual colors in a palette dictionary. In plt.fill
, alpha
applies both to the face and the edge color. You can use to_rgba
to give a transparrency to the face color while using the edge color without alpha.
import pandas as pd
import numpy as np
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
from matplotlib.colors import to_rgba
import seaborn as sns
sns.set_style('whitegrid')
data = sns.load_dataset("penguins")
xcol = 'bill_length_mm'
ycol = 'bill_depth_mm'
hues = data["sex"].unique()
colors = sns.color_palette("Paired", len(hues))
palette = {hue_val: color for hue_val, color in zip(hues, colors)}
g = sns.relplot(data=data, x=xcol, y=ycol, hue="sex", style="sex", col='species', palette=palette, kind='scatter')
def overlay_cv_hull_dataframe(x, y, color, data, hue):
# Get the Convex Hull for each group based on hue
for hue_val, group in data.groupby(hue):
hue_color = palette[hue_val]
points = group[[x, y]].values
hull = ConvexHull(points)
plt.fill(points[hull.vertices, 0], points[hull.vertices, 1],
facecolor=to_rgba(hue_color, 0.2),
edgecolor=hue_color)
# Overlay convex hulls
g.map_dataframe(overlay_cv_hull_dataframe, x=xcol, y=ycol, hue='sex')
g.set_axis_labels(xcol, ycol)
plt.show()
I’m trying to overlay shaded convex hulls to the different groups in a scatter seaborn.relplot
using Matplotlib. Based on this question and the Seaborn example, I’ve been able to successfully overlay the convex hulls for each sex
in the penguins dataset.
# Import libraries
import pandas as pd
import numpy as np
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
data = sns.load_dataset("penguins")
xcol = 'bill_length_mm'
ycol = 'bill_depth_mm'
g = sns.relplot(data = data, x=xcol, y = ycol,
hue = "sex", style = "sex",
col = 'species', palette="Paired",
kind = 'scatter')
def overlay_cv_hull_dataframe(x, y, color, **kwargs):
data = kwargs.pop('data')
# Get the Convex Hull for each group based on hue
for _, group in data.groupby('hue'):
points = group[['x', 'y']].values
hull = ConvexHull(points)
for simplex in hull.simplices:
plt.fill(points[simplex, 0], points[simplex, 1],
facecolor = color, alpha=0.5,
edgecolor = color)
# Overlay convex hulls
g.map_dataframe(overlay_cv_hull_dataframe, x=xcol, y=ycol,
hue='sex')
g.set_axis_labels(xcol, ycol)
However, the convex hulls are not filled in with the same color as the edge, even though I specified that
plt.fill(points[simplex, 0], points[simplex, 1],
facecolor = color, alpha=0.5,
edgecolor = color, # color is an RGB tuple like (0.12, 0.46, 0.71)
)
I’ve also tried setting facecolor='lightsalmon'
like this example and removing the alpha
parameter, but get the same plot. I think I’m really close but I’m not sure what else to try.
How can I get the convex hulls to be filled with the same color
as edgecolor
and the points?
(Your code seems to have some typos, writing 'x'
, 'y'
and 'hue'
instead of x
, y
and hue
).
simplex
contains the indices of the coordinates of one edge of the convex hull. To fill a polygon, you need all edges, or hull.vertices
.
g.map_dataframe
only calls the function once per subplot. As such, color
is only usable if you wouldn’t be using hue
. Instead, you’ll need to store the individual colors in a palette dictionary. In plt.fill
, alpha
applies both to the face and the edge color. You can use to_rgba
to give a transparrency to the face color while using the edge color without alpha.
import pandas as pd
import numpy as np
from scipy.spatial import ConvexHull
import matplotlib.pyplot as plt
from matplotlib.colors import to_rgba
import seaborn as sns
sns.set_style('whitegrid')
data = sns.load_dataset("penguins")
xcol = 'bill_length_mm'
ycol = 'bill_depth_mm'
hues = data["sex"].unique()
colors = sns.color_palette("Paired", len(hues))
palette = {hue_val: color for hue_val, color in zip(hues, colors)}
g = sns.relplot(data=data, x=xcol, y=ycol, hue="sex", style="sex", col='species', palette=palette, kind='scatter')
def overlay_cv_hull_dataframe(x, y, color, data, hue):
# Get the Convex Hull for each group based on hue
for hue_val, group in data.groupby(hue):
hue_color = palette[hue_val]
points = group[[x, y]].values
hull = ConvexHull(points)
plt.fill(points[hull.vertices, 0], points[hull.vertices, 1],
facecolor=to_rgba(hue_color, 0.2),
edgecolor=hue_color)
# Overlay convex hulls
g.map_dataframe(overlay_cv_hull_dataframe, x=xcol, y=ycol, hue='sex')
g.set_axis_labels(xcol, ycol)
plt.show()