3

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.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Ninja_star
  • 57
  • 1
  • 5
  • @JohanC - I think I am using updated versions; I just checked and my Matplotlib is v 3.5.1 and my seaborn is v 0.11.2 (from a quick google search, I think those are the newer versions) – Ninja_star Mar 13 '22 at 19:52
  • 1
    (The recommended way to change the colors in Seaborn is to convert the dataframe to long form via `random_df.melt()` and then use `hue='variable'` and `palette=...`) – JohanC Mar 13 '22 at 20:20
  • @JohanC - could you point to some examples of where I can learn more about the method where I use `df.melt()`, etc.? – Ninja_star Mar 13 '22 at 22:02
  • 2
    [Data structures accepted by seaborn](https://seaborn.pydata.org/tutorial/data_structure.html#data-structures-accepted-by-seaborn) – tdy Mar 13 '22 at 22:21

1 Answers1

1

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

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • How do you change the line color? I tried a number of different approaches with the `for i,artist in enumerate(ax2.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')` and none of them worked... – Justyna May 20 '22 at 23:11
  • @Justyna Your code seems to update the colors of the box, not the median, nor the whiskers nor the fliers. Maybe you can create a new question, as it is something different? – JohanC May 21 '22 at 08:46
  • This code is an excerpt from https://stackoverflow.com/questions/36874697/how-to-edit-properties-of-whiskers-fliers-caps-etc-in-seaborn-boxplot/36893152#36893152 showing how to change colors of boxplot lines -- I tried to to run a copy-pasted version of it and it seems to not work in seaborn 0.11.2. I'll post a new question about it. – Justyna May 21 '22 at 10:03
  • I added a new answer to the linked post. See [here](https://stackoverflow.com/questions/36874697/how-to-edit-properties-of-whiskers-fliers-caps-etc-in-seaborn-boxplot/72333641#72333641) – JohanC May 21 '22 at 22:44