Make box plots indexed by another column in python

Viewed 169

I have the following dataframe:

   Month      Value
--------------------
 January         34
 January         34 
 January         75 
...
February         45
February         77
February         45  
...
     May         24
     May         26
     May         44
... 
November         76  
November         25
November         74 
...
December         76  
December         96
December         58

Each month name corresponds to a different "Period". Here is that key (not code):

Period 1: January through April
Period 2: May through July
Period 3: August through December

I add a column to my dataframe that assigns the appropriate "Period" to each row using:

df.loc[df.Month == ('January'), 'Period'] = "Period 1"
df.loc[df.Month == ('February'), 'Period'] = "Period 1"
df.loc[df.Month == ('March'), 'Period'] = "Period 1"
df.loc[df.Month == ('April'), 'Period'] = "Period 1"
df.loc[df.Month == ('May'), 'Period'] = "Period 2"
df.loc[df.Month == ('June'), 'Period'] = "Period 2"
df.loc[df.Month == ('July'), 'Period'] = "Period 2"
df.loc[df.Month == ('August'), 'Period'] = "Period 2"
df.loc[df.Month == ('September'), 'Period'] = "Period 3"
df.loc[df.Month == ('October'), 'Period'] = "Period 3"
df.loc[df.Month == ('November'), 'Period'] = "Period 3"
df.loc[df.Month == ('December'), 'Period'] = "Period 3"

This produces the following:

   Month        Period     Value
---------------------------------
 January      Period 1        34
 January      Period 1        34 
 January      Period 1        75 
...
February      Period 1        45
February      Period 1        77
February      Period 1        45  
...
     May      Period 2        24
     May      Period 2        26
     May      Period 2        44
... 
November      Period 3        76  
November      Period 3        25
November      Period 3        74 
...
December      Period 3        76  
December      Period 3        96
December      Period 3        58

Now, I create a single box plot chart that contains 3 box plots, with "Value" as the y-axis, and "Period" as the x-axis using the following code:

df.boxplot(column = 'Value', by = 'Period');
plt.suptitle("")
plt.title("Value for each Period")
plt.ylim(0, 5)
plt.ylabel("Value")

This creates a single chart with 4 box plot "boxes", with "Value" on the y-axis. Each box represents a separate "Period", so a box for Period 1, a box for Period 2, and a box for Period 3. Now, what I am having trouble with and am trying to figure out how to do, is to add a fourth box to this single chart that represents data from all three periods, and so an "Annual" box. How can I set up a fourth box plot for this fourth "Annual" box that incorporates data from all months? I am working python.

I tried this:

df.loc[df.Month == ('January', 'February', 'March', 'April', 'May', 'June', 
                      'July', 'August', 'September', 'October', 'November', 'December'), 'Period'] = "Annual"

But this leads to a logical error of whether each month belongs to its corresponding "Period" or to the "Annual" period.

1 Answers

I think there are a number of ways to do this, including simply using a subplot, but if you really want the boxplot on the same figure axis, then this should work:

ax = df.boxplot(column = 'Value', by = 'Period')
xticklabels = [text.get_text() for text in ax.get_xticklabels()]
xticklabels.append("All Periods")
# This second boxplot call messes up the xticklabels
df.boxplot(column='Value', ax=ax, **{'positions': [4]})
fh = ax.get_figure()
fh.suptitle("")
ax.set_title("Value for each Period")
ax.set_ylabel("Value")
ax.set_xticklabels(xticklabels)

This builds another boxplot using the existing dataframe as is. This is done by omiting the by keyword on a second boxplot call so all data is used, the axis is explicitly set to be the same one used for the first three boxplots, and the position of the fourth, new boxplot is set to position 4. The 'positions' array defaults to range(1, N+1), so first three boxplots are located at [1, 2, 3], see docs.

The xticklabels are stored right after they're constructed on the first boxplot call so you make sure they're in the right order, then add the label for the summary boxplot to the end of the list. Reset the xticklabels at the end and I think this gives you what you wanted if I understand correctly. enter image description here

Related