Pandas boxplot: set color and properties for box, median, mean
I just found another solution to plot with much less code directly from pandas (without having to manipulate the matplotlib-object afterwards):
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.rand(10, 5), columns=['A', 'B', 'C', 'D', 'E'])
ax = df.plot(kind='box',
color=dict(boxes='r', whiskers='r', medians='r', caps='r'),
boxprops=dict(linestyle='-', linewidth=1.5),
flierprops=dict(linestyle='-', linewidth=1.5),
medianprops=dict(linestyle='-', linewidth=1.5),
whiskerprops=dict(linestyle='-', linewidth=1.5),
capprops=dict(linestyle='-', linewidth=1.5),
showfliers=False, grid=True, rot=0)
ax.set_xlabel('Foo')
ax.set_ylabel('Bar in X')
plt.show()
yields:
The only thing I haven't figured out is how to adjust the color of the means when showmeans=True
. But in most cases this should be fine..
Hope it helps!
Screenpavers answer worked well.
Here's a complete example:
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
# dataframe with dates
dates = pd.DataFrame()
dates['2016'] = pd.date_range(start='2016', periods=4, freq='60Min')
dates['2017'] = pd.date_range(start='2017', periods=4, freq='60Min')
dates['2018'] = pd.date_range(start='2018', periods=4, freq='60Min')
dates.reset_index()
dates = dates.unstack()
# multi-indexed dataframe
df = pd.DataFrame(np.random.randn(36, 3))
df['concept'] = np.repeat(np.repeat(['A', 'B', 'C'], 3), 4)
df['datetime'] = pd.concat([dates, dates, dates], ignore_index=True)
df.set_index(['concept', 'datetime'], inplace=True)
df.sort_index(inplace=True)
df.columns = ['V1', 'V2', 'V3']
df.info()
# demonstrate how to customize the display different elements:
boxprops = dict(linestyle='-', linewidth=4, color='k')
medianprops = dict(linestyle='-', linewidth=4, color='k')
bp = df.boxplot(column=['V1'],
by=df.index.get_level_values('datetime').year,
showfliers=False, showmeans=True,
boxprops=boxprops, medianprops=medianprops,
return_type='dict')
# boxplot style adjustments
[[item.set_linewidth(4) for item in bp[key]['boxes']] for key in bp.keys()]
[[item.set_linewidth(4) for item in bp[key]['fliers']] for key in bp.keys()]
[[item.set_linewidth(4) for item in bp[key]['medians']] for key in bp.keys()]
[[item.set_linewidth(4) for item in bp[key]['means']] for key in bp.keys()]
[[item.set_linewidth(4) for item in bp[key]['whiskers']] for key in bp.keys()]
[[item.set_linewidth(4) for item in bp[key]['caps']] for key in bp.keys()]
[[item.set_color('g') for item in bp[key]['boxes']] for key in bp.keys()]
# seems to have no effect
[[item.set_color('b') for item in bp[key]['fliers']] for key in bp.keys()]
[[item.set_color('m') for item in bp[key]['medians']] for key in bp.keys()]
[[item.set_markerfacecolor('k') for item in bp[key]['means']] for key in bp.keys()]
[[item.set_color('c') for item in bp[key]['whiskers']] for key in bp.keys()]
[[item.set_color('y') for item in bp[key]['caps']] for key in bp.keys()]
# get rid of "boxplot grouped by" title
plt.suptitle("")
# label adjustment
p = plt.gca()
p.set_xlabel("")
p.set_title("Some plot", fontsize=30)
p.tick_params(axis='y', labelsize=30)
p.tick_params(axis='x', labelsize=30)
returns:
Before your bp.set_xlabel("")
statement, try this instead:
p = plt.gca()
p.set_xlabel("")
p.set_title("Some plot", fontsize=60)
p.tick_params(axis='y', labelsize=60)
p.tick_params(axis='x', labelsize=60)