Vinod Kumar
Vinod Kumar

Reputation: 1622

Assign color of mean markers while using seaborn hue

In Seaborn, I can assign the color of mean marker by providing meanprops e.g. :

meanprops: {'marker': 'o', 'markeredgecolor': c,
                    'markerfacecolor': 'none', 'markersize': 4}

However, if I make a plot using hue, this will set same colour of mean to all the categories. How can i also apply hue color to mean also.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
df_merge = pd.DataFrame(data={'AOD_440nm': np.random.rand(20),
                        'month': np.tile(['Jan','Feb'], 10),
                        'kind': np.repeat(['A', 'B'], 10)})
fig,ax = plt.subplots()
sns.boxplot(x='month', y='AOD_440nm', hue='kind', data=df_merge,
            showfliers=False, whis=[5, 95],
            palette=sns.color_palette(('r', 'k')),
            showmeans=True)
for i, artist in enumerate(ax.artists):
    # Set the linecolor on the artist to the facecolor, and set the facecolor to None
    col = artist.get_facecolor()
    artist.set_edgecolor(col)
    artist.set_facecolor('None')

In short, how can I change colour of means?

Upvotes: 4

Views: 1192

Answers (1)

JohanC
JohanC

Reputation: 80279

You could loop through all the "lines" generated by the boxplot. The boxplot generates multiple lines per box, one for each element. The marker for the mean is also a "line", but with linestyle None, only having a marker (similar to how plt.plot can draw markers). The exact amount of lines per box depends on the options (as in: with/without mean, whiskers, ...). As changing the marker color of the non-marker lines doesn't have visible effect, changing all marker colors is the easiest approach.

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

df_merge = pd.DataFrame(data={'AOD_440nm': np.random.rand(20),
                              'month': np.tile(['Jan', 'Feb'], 10),
                              'kind': np.repeat(['A', 'B'], 10)})
fig, ax = plt.subplots()
sns.boxplot(x='month', y='AOD_440nm', hue='kind', data=df_merge,
            showfliers=False, whis=[5, 95],
            palette=sns.color_palette(('r', 'k')),
            showmeans=True)

num_artists = len(ax.artists)
num_lines = len(ax.lines)
lines_per_artist = num_lines // num_artists
for i, artist in enumerate(ax.artists):
    # Set the linecolor on the artist to the facecolor, and set the facecolor to None
    col = artist.get_facecolor()
    artist.set_edgecolor(col)
    artist.set_facecolor('None')
    # set the marker colors of the corresponding "lines" to the same color
    for j in range(lines_per_artist):
        ax.lines[i * lines_per_artist + j].set_markerfacecolor(col)
        ax.lines[i * lines_per_artist + j].set_markeredgecolor(col)
plt.show()

example plot

PS: An alternative to artist.set_facecolor('None') could be to use a strong transparency: artist.set_alpha(0.1).

using transparency

Upvotes: 2

Related Questions