Creating a boxplot FacetGrid in Seaborn for python
Asked Answered
M

4

7

I'm trying to create a 4x4 FacetGrid in seaborn for 4 boxplots, each of which is split into 3 boxplots based on the iris species in the iris dataset. Currently, my code looks like this:

sns.set(style="whitegrid")
iris_vis = sns.load_dataset("iris")

fig, axes = plt.subplots(2, 2)

ax = sns.boxplot(x="Species", y="SepalLengthCm", data=iris, orient='v', 
    ax=axes[0])
ax = sns.boxplot(x="Species", y="SepalWidthCm", data=iris, orient='v', 
    ax=axes[1])
ax = sns.boxplot(x="Species", y="PetalLengthCm", data=iris, orient='v', 
    ax=axes[2])
ax = sns.boxplot(x="Species", y="PetalWidthCm", data=iris, orient='v', 
    ax=axes[3])

However, I'm getting this error from my interpreter:

AttributeError: 'numpy.ndarray' object has no attribute 'boxplot'

I'm confused on where the attribute error is exactly in here. What do I need to change?

Marker answered 24/9, 2018 at 4:34 Comment(0)
C
3

axes shape is (nrows, ncols). In this case is:

array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7f4267f425f8>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x7f4267f1bb38>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x7f4267ec95c0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x7f4267ef9080>]],
      dtype=object)

So, when you do ax=axes[0] you get a array and not the axes. Try:

fig, axes = plt.subplots(2, 2)

ax = sns.boxplot(x="Species", y="SepalLengthCm", data=iris, orient='v', 
    ax=axes[0, 0])
ax = sns.boxplot(x="Species", y="SepalWidthCm", data=iris, orient='v', 
    ax=axes[0, 1])
ax = sns.boxplot(x="Species", y="PetalLengthCm", data=iris, orient='v', 
    ax=axes[1, 0])
ax = sns.boxplot(x="Species", y="PetalWidthCm", data=iris, orient='v', 
    ax=axes[1, 1])

example_plot

Cordon answered 24/9, 2018 at 6:12 Comment(0)
C
11

Not a direct answer to your error, but if you are going to use seaborn, you should try to stick with "long" or "tidy" data (https://seaborn.pydata.org/tutorial/data_structure.html#long-form-data).

I'm assuming your original data set is wide (column for each feature of the observation). If you melt the data set like so:

iris = iris.melt(id_vars='target')

print(iris.head())

   target           variable  value
0  setosa  sepal length (cm)    5.1
1  setosa  sepal length (cm)    4.9
2  setosa  sepal length (cm)    4.7
3  setosa  sepal length (cm)    4.6
4  setosa  sepal length (cm)    5.0

You'll be able to use seaborn's catplot with kind='box'

sns.catplot(
    data=iris, x='target', y='value',
    col='variable', kind='box', col_wrap=2
)

boxplot

Capitalize answered 26/10, 2020 at 16:20 Comment(2)
add sharey = False within the sns.catplot call to make the y-axis different for each variable if you like to get more resolution for each variableActinomycosis
I do prefer this methodSimplistic
C
3

axes shape is (nrows, ncols). In this case is:

array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7f4267f425f8>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x7f4267f1bb38>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x7f4267ec95c0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x7f4267ef9080>]],
      dtype=object)

So, when you do ax=axes[0] you get a array and not the axes. Try:

fig, axes = plt.subplots(2, 2)

ax = sns.boxplot(x="Species", y="SepalLengthCm", data=iris, orient='v', 
    ax=axes[0, 0])
ax = sns.boxplot(x="Species", y="SepalWidthCm", data=iris, orient='v', 
    ax=axes[0, 1])
ax = sns.boxplot(x="Species", y="PetalLengthCm", data=iris, orient='v', 
    ax=axes[1, 0])
ax = sns.boxplot(x="Species", y="PetalWidthCm", data=iris, orient='v', 
    ax=axes[1, 1])

example_plot

Cordon answered 24/9, 2018 at 6:12 Comment(0)
B
3

Because as @Lucas points out that axes returns a numpy array of 2D(nrows, ncols), you can flatten this array 1D using:

axes=axes.flatten()

And, you can keep your same code like this:

fig, axes = plt.subplots(2, 2)
axes = axes.flatten()

ax = sns.boxplot(x="Species", y="SepalLengthCm", data=iris, orient='v', 
    ax=axes[0])
ax = sns.boxplot(x="Species", y="SepalWidthCm", data=iris, orient='v', 
    ax=axes[1])
ax = sns.boxplot(x="Species", y="PetalLengthCm", data=iris, orient='v', 
    ax=axes[2])
ax = sns.boxplot(x="Species", y="PetalWidthCm", data=iris, orient='v', 
    ax=axes[3])

Output:

enter image description here

Berman answered 24/9, 2018 at 15:5 Comment(0)
I
0

Or just making the above more concise:

cat_variables = ['SepalLengthCm', 'SepalWidthCm', 'PetalLengthCm', 'PetalWidthCm']
x_var = "Species"
fig, axes = plt.subplots(len(cat_variables)/2, len(cat_variables)/2, figsize=(15,15))
axes = axes.flatten()

i = 0
for t in cat_variables:
    ax = sns.boxplot(x=x_var, y=TARGET, data=iris, orient='v', 
    ax=axes[i])
    i +=1
Idonna answered 25/8, 2019 at 23:6 Comment(1)
Gettring error: TypeError: 'float' object cannot be interpreted as an integerGoatish

© 2022 - 2024 — McMap. All rights reserved.