boxplot show max and min fliers results in TypeError: 'AxesSubplot' object is not subscriptable

Viewed 270

I am preparing box plots with a whisker interval of [2,98]. The issue is that I am working with air quality data and have a large range of data points, so the outliers take up the entire figure and overshadow the boxplots. I would like to plot the max and min outliers only and have tried the method from Matplotlib boxplot show only max and min fliers, however, I get an error message that says TypeError: 'AxesSubplot' object is not subscriptable.

Here is my code:

fig,ax = plt.subplots(1, figsize=(8,6))
g = sns.boxplot(data=mda8, orient='v', width = 0.7, whis = (2,98))
fliers = g['fliers']
for fly in fliers:
    fdata=fly.get_data
    fly.set_data([fdata[0][0],fdata[0][-1],fdata[1][0],fdata[1][-1]])
xvalues = ['Niland', 'El Centro', 'Calexico']
plt.xticks(np.arange(3), xvalues, fontsize=12)
ax.set_ylabel('Ozone MDA8 (ppb)',fontsize=15)
ax.set_ylim(0,105)
plt.show()

Here's some sample data:

mda8 = pd.DataFrame({
'T1':[35.000000, 32.125000, 32.000000, 35.250000, 28.875000, 28.500000, 29.375000, 25.125000, 34.166667, 35.250000],
'T2':[28.375, 30.750, 33.250, 34.000, 32.875, 30.250, 29.875, 100.409, 29.625, 1.232],
'T3':[34.250, 102.232, 28.250, 33.000, 27.625, 21.500, 28.375, 30.250, 3.454, 33.750]})

I need help with plotting the max and min outliers only and am open to doing another method besides the one that I tried here.

EDIT here's the link to my csv file https://drive.google.com/file/d/1E3A0UAYCbSN53JXtfsbrA4i_Phci_JWf/view?usp=sharing

1 Answers

A possible approach could be:

  • hide the outliers plotted by seaborn.boxplot by passing showfliers = False parameter:

    sns.boxplot(data=mda8, orient='v', width = 0.7, whis = (2,98), showfliers = False)
    
  • get the list of outliers for each column, find maximum and minimum and plot only them:

    outliers = {col: list(stat['fliers']) for col in mda8.columns for stat in boxplot_stats(mda8[col])}
    min_max_outliers = {key: [np.min(value), np.max(value)] if value != [] else [] for key, value in outliers.items()}
    
    i = 0
    for key, value in min_max_outliers.items():
        if value != []:
            ax.scatter([i, i], value, marker = 'd', facecolor = 'black')
        i += 1
    

Complete Code

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


mda8 = pd.DataFrame({'T1': [35.000000, 32.125000, 32.000000, 35.250000, 28.875000, 28.500000, 29.375000, 25.125000, 34.166667, 35.250000],
                     'T2': [28.375, 30.750, 33.250, 34.000, 32.875, 30.250, 29.875, 100.409, 29.625, 1.232],
                     'T3': [34.250, 102.232, 28.250, 33.000, 27.625, 21.500, 28.375, 30.250, 3.454, 33.750]})


fig,ax = plt.subplots(1, figsize=(8,6))

sns.boxplot(data=mda8, orient='v', width = 0.7, whis = (2,98), showfliers = False)

outliers = {col: list(stat['fliers']) for col in mda8.columns for stat in boxplot_stats(mda8[col])}
min_max_outliers = {key: [np.min(value), np.max(value)] if value != [] else [] for key, value in outliers.items()}

i = 0
for key, value in min_max_outliers.items():
    if value != []:
        ax.scatter([i, i], value, marker = 'd', facecolor = 'black')
    i += 1

xvalues = ['Niland', 'El Centro', 'Calexico']
plt.xticks(np.arange(3), xvalues, fontsize=12)
ax.set_ylabel('Ozone MDA8 (ppb)',fontsize=15)
ax.set_ylim(0,105)

plt.show()

enter image description here


EDIT

Working on the data your provided, if I plot them as they are:

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


mda8 = pd.read_csv(r'data/MDA8_allregions.csv')
mda8 = mda8.drop(['date', 'date.1', 'date.2'], axis = 1)


fig, ax = plt.subplots(1, figsize = (8, 6))

sns.boxplot(data = mda8, orient = 'v', width = 0.7, whis = (2, 98), showfliers = True)

plt.show()

I get:

enter image description here

In the code above I change the parameter showfliers = False, in order to hide outliers.
Then, as suggested by JohanC in the comment, a simpler way to plot outliers is to plot min and max for each column:

for i, col in enumerate(mda8.columns, 0):
    ax.scatter([i, i], [mda8[col].min(), mda8[col].max()], marker = 'd', facecolor = 'black')

Complete Code

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


mda8 = pd.read_csv(r'data/MDA8_allregions.csv')
mda8 = mda8.drop(['date', 'date.1', 'date.2'], axis = 1)


fig, ax = plt.subplots(1, figsize = (8, 6))

sns.boxplot(data = mda8, orient = 'v', width = 0.7, whis = (2, 98), showfliers = False)

for i, col in enumerate(mda8.columns, 0):
    ax.scatter([i, i], [mda8[col].min(), mda8[col].max()], marker = 'd', facecolor = 'black')

plt.show()

enter image description here

Related