mwaskom/seaborn

Stripplot edgecolor uses different palette for first category

Closed this issue · 16 comments

I'd like to create a stripplot like this one, but with edgecolor specified by a palette:
this one

Here is my attempt:

import seaborn as sns
df = sns.load_dataset("tips")
ax = sns.stripplot(x="sex", y="tip", hue="day", data=df, jitter=True, edgecolor=sns.color_palette("hls", 4), facecolors="none", split=False, alpha=0.7)

But the resulting figure uses a different palette for the first category and the legend than what I tried to specify:
stripplot_test

Is this expected behavior or a bug?

The edgecolor parameter is just passed straight through to plt.scatter. Currently you're giving it a list of 4 colors. I'm not exactly sure what I would expect it to do in that case, but I wouldn't really expect it to "work". In general, it's not possible to map the hue variable to the edgecolor in stripplot. It might work in cases where you have perfectly balanced data, but you'll want to not use hue, and instead pass a vector of colors that is the length of the data in each x bin. You also won't get a legend this way, so I'm not sure it's ideal.

FWIW I think it can be pretty hard to discriminate the colors of the edges in this example. Your specific usecase might be a bit different, and I could imagine some special cases where it works (e.g. a lot of gray points and a few highlighted colored points), but I'm not sure this is generally the best approach.

Ah, I guess this is more of a feature request then.

I agree that the colors of the edges in this example are tough to distinguish, but in general I find hollow points useful since they don't mask things underneath them.

Yeah, I can see why you would want to do it. I think making this an option in stripplot would be bad from an API and implementation standpoint. It's messy. It would also be annoying because you'd probably want this in other scatter based seaborn functions.

From my perspective, the ideal would be if matplotlib offered a "hollow circle" marker where the color/facecolor attribute modified the color of the circular edge. However, I can also see why they might not want to do this.

That said, with a bit of a hack, it's not hard to make one ourselves:

import numpy as np
import matplotlib as mpl
import seaborn as sns

sns.set_style("whitegrid")
df = sns.load_dataset("tips")

pnts = np.linspace(0, np.pi * 2, 24)
circ = np.c_[np.sin(pts) / 2, -np.cos(pts) / 2]
vert = np.r_[circ, circ[::-1] * .7]

open_circle = mpl.path.Path(vert)

sns.stripplot(x="sex", y="tip", hue="day", data=df,
              jitter=True, split=False,
              palette="hls", marker=open_circle, linewidth=.001)

open_circle

Hmm... would it make sense to implement a set of custom open markers in seaborn? That way it would work for other scatter-based functions. Syntax like:

marker=sns.custom_markers.open_circle

wouldn't be too messy.

I'm not sure. Although this basically works, it does feel a lot like a hack. Plus it's not totally self-contained in that you still need to know to set the linewidth to 0 or else the edges will totally overwhelm the glyph. Perhaps if there were some way to make it so the Path object will just ignore the linewidth, but again, that would be kind of hacky...

I believe my issue falls under this ticket. I want to make a stripplot with hollow markers that are separated into two groups per category, but it is not working as expected:

sns.stripplot("day", "total_bill", "smoker", data=tips, facecolor='white', edgecolor='gray')

image

I tried the suggested workaround, but it just gives me hollow markers of the same color distribution as in my plot above. Is it possible to plot the grey hollow markers for all weekdays in the sample plot?

I don't think I understand. You want all of the points to be round with a white face and gray edges? How will you know what group is what?

I am overlaying another marker, so it will be clear from the color of this marker. I forgot to add that if I leave out the hue parameter ("smoker"). Everything works as expected and all weekdays have hollow gray markers.

I don't think it's possible to use hue but not have different colors applied, sorry.

But it does work for all the other weekdays except Thursday. So it seems to be possible, just not applied to Thursday.

To clarify, my end result would be something like this, showing both the distribution and mean value.
image

I don't know why that "works", but it's not officially supported behavior.

You could always just pass ["w", "w"] as your palette...

I was trying that, but it wouldn't work. Now I tried again and it turns out I needed to remove the facecolor parameter.

This works:

sns.stripplot("day", "total_bill", "smoker", data=tips, palette=['w']*2, edgecolor='gray')

image

But this doesn't:

sns.stripplot("day", "total_bill", "smoker", data=tips, palette=['w']*2, facecolor='white', edgecolor='gray')

image

Now I have a way to create the plot I want, thanks!

Would it be appropriate to support edgecolor='hue'?

Closing because this works:

ax = sns.stripplot(x="sex", y="tip", hue="day", data=tips,
                   marker="$\circ$", size=10,
                   jitter=True, alpha=0.7)

image

Closing because this works:

ax = sns.stripplot(x="sex", y="tip", hue="day", data=tips,
                   marker="$\circ$", size=10,
                   jitter=True, alpha=0.7)

image

These circles actually have their center to the left border of the circle, and not in their middle. So if you want to use jitter=False, the markers will be slightly to the right. Do you have a solution for this? Neither of the above comments solve this problem.