How to color each boxplot differently

Viewed 664

I am trying to make a Seaborn box plot in VSCode. I am basing my code off this example here: here. I am specifically making something like the penultimate example, but without the annotation.

Code:

# 0. Import the modules
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns


# 1. Import the data
random_df = pd.DataFrame(data = {'0': np.random.rand(10),
                                 '1': np.random.rand(10),
                                 '2': np.random.rand(10),
                                 '3': np.random.rand(10),
                                 '4': np.random.rand(10)})

# 2. Do the plotting

# set style - When adding multple boxplots I like use whitegird 
sns.set(style='whitegrid')

fig, ax = plt.subplots(figsize=(12,9))
g = sns.boxplot(data = random_df, width = 0.7)              

# with a descriptive title a ylabel might not be necessary
plt.ylabel("Accuracy", fontsize = 14)

# X tick-labels
# we are including this because I want the full product name not the variable name
xvalues = ["Label 1", "Label 2", "Label 3", "Label 4", "Label 5"] 

# set xvalues as xtick values
plt.xticks(np.arange(5), xvalues)

# remove all borders except bottom
sns.despine(top=False,
            right=True,
            left=True,
            bottom=False)

# Set colors of box plots 
palette= ['plum','g','orange','b','r']
color_dict = dict(zip(xvalues, palette))

for i in range(0,5):
    mybox = g.artists[i]
    mybox.set_facecolor(color_dict[xvalues[i]])  

plt.tight_layout()
plt.show()

Problem:

When I run the code in VSCode, I am getting the following error: 'index out of range'. This is pertaining to the line g.artists[i]; when I take that for loop out of my code, then the box plot can work. Also, this code only yields an error when I am using it in VSCode. When I run the code in Google Colab, then there is no error.

1 Answers

In matplotlib 3.5 the boxes are stored in ax.patches instead of ax.artists.

The recommended way to change the colors in Seaborn is to convert the dataframe to long form via pandas' melt() and then use hue= on the same variable as x= together with palette=. (palette can be, among others, a dictionary or a list of colors.)

By changing the column names temporarily, the x tick labels will be set automatically. If the ax has been created beforehand, passing it as a parameter tells seaborn to plot onto that ax. (Axes-level functions return the ax onto which the plot was created; when the ax is given as parameter, there is no need to store the return value.)

Here is an example:

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

random_df = pd.DataFrame(data={'0': np.random.rand(10),
                               '1': np.random.rand(10),
                               '2': np.random.rand(10),
                               '3': np.random.rand(10),
                               '4': np.random.rand(10)})
sns.set(style='whitegrid')

fig, ax = plt.subplots(figsize=(12, 9))
xvalues = ["Label 1", "Label 2", "Label 3", "Label 4", "Label 5"]
palette = ['plum', 'g', 'orange', 'b', 'r']

melted_df = random_df.set_axis(xvalues, axis=1).melt(var_name='Variable', value_name='Accuracy')
sns.boxplot(data=melted_df, x='Variable', y='Accuracy', hue='Variable', palette=palette,
            width=0.7, dodge=False, ax=ax)

ax.legend_.remove()  # remove the legend, as the information is already present in the x labels
ax.set_xlabel('')  # remove unuseful xlabel ('Variable')
ax.set_ylabel("Accuracy", fontsize=14)

sns.despine(top=True, right=True, left=True, bottom=False)
plt.show()

sns.boxplot on long form dataframe

Related