Matplotlib boxplot legend without using ax

340 Views Asked by At

Is there any way of creating boxplot legend in matplotlib without using the return value of ax.boxplot() as in Adding a legend to a matplotlib boxplot with multiple plots on same axes?

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

n = 480
ts = pd.Series(np.random.randn(n), index=pd.date_range(start="2014-02-01", periods=n, freq="H"))
for i, frame in zip(range(ts.index.dayofyear.nunique()), 
                        ts.index.dayofyear.unique()):
    plt.boxplot(ts[ts.index.dayofyear == frame], positions=[i], widths=0.9)

Above is just toy example code. In my project I actually call plt.boxplot() in the separate function each time (several calls of the function but the same axis is used) and I do not want to make any new return and parameter values.

Is there a way to create a legend for boxplots without using those return values as in other types of plots (by passing label=...)?

1

There are 1 best solutions below

2
On

Since you are using a Pandas series, consider a Pandas plot solution that still interfaces with matplotlib. You will need to first upcast series to a data frame and assign needed hour and day indicator columns. With this approach, you can pass ax object as an argument and use that for additional needs or use defaults with DataFrame.plot:

# CONVERT TO DATA FRAME WITH day AND hour COLUMNS
ts_df = (ts.to_frame()
           .rename({0:'value'}, axis='columns')
           .assign(hour = lambda x: x.index.hour,
                   dayofyear = lambda x: x.index.dayofyear)
        )

ts_df.head()            
#                         value  hour  dayofyear
# 2014-02-01 00:00:00 -0.555308     0         32
# 2014-02-01 01:00:00  0.720157     1         32
# 2014-02-01 02:00:00 -1.140971     2         32
# 2014-02-01 03:00:00 -0.359197     3         32
# 2014-02-01 04:00:00 -2.241330     4         32

seaborn.set()
for i, g in ts_df.groupby(['dayofyear']):
    myfig, myaxes = plt.subplots(figsize = (8,4))
    g['value'].plot(kind = 'box', ax = myaxes, 
                        title = 'Hourly Value Boxplot in Day {}'.format(i))
    # myaxes.legend(...)

    plt.show()  

First Plot Output

Alternatively, if you need all boxplots in one plot, pivot the data for day columns:

ts_pvt_df = ts_df.pivot(index='hour', columns = 'dayofyear', values = 'value')

seaborn.set()
myfig, myaxes = plt.subplots(figsize = (12,6))
ts_pvt_df.plot(kind = 'box', ax = myaxes, title = 'Hourly Value Boxplots by Day')

plt.show()  

Second Plot Output