This is in reference to the following question, wherein options for adjusting title and layout of subplots are discussed: modify pandas boxplot output
My requirement is to change the colors of individual boxes in each subplot (as depicted below):
Following is the code available at the shared link for adjusting the title and axis properties of subplots:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])
df['models'] = pd.Series(np.repeat(['model1','model2', 'model3', 'model4', 'model5', 'model6', 'model7'], 20))
bp = df.boxplot(by="models",layout=(4,1),figsize=(6,8))
[ax_tmp.set_xlabel('') for ax_tmp in np.asarray(bp).reshape(-1)]
fig = np.asarray(bp).reshape(-1)[0].get_figure()
fig.suptitle('New title here')
plt.show()
I tried using the: ax.set_facecolor('color') property, but not successful in obtaining the desired result.
I tried accessing bp['boxes'] as well but apparently it is not available. I need some understanding of the structure of data stored in bp for accessing the individual boxes in the subplot.
Looking forward
P.S: I am aware of seaborn. But need to understand and implement using df.boxplot currently. Thanks
To colorize the boxplot, you need to first use the patch_artist=True keyword to tell it that the boxes are patches and not just paths. Then you have two main options here: set the color via ... props keyword argument, e.g.
To change the color of box of boxplot in base R, we can use col argument inside boxplot function.
To adjust the colours of your boxes in pandas.boxplot
, you have to adjust your code slightly. First of all, you have to tell boxplot
to actually fill the boxes with a colour. You do this by specifying patch_artist = True
, as is documented here. However, it appears that you cannot specify a colour (default is blue) -- please anybody correct me if I'm wrong. This means you have to change the colour afterwards. Luckily pandas.boxplot
offers an easy option to get the artists in the boxplot as return value by specifying return_type = 'both'
see here for an explanation. What you get is a pandas.Series
with keys according to your DataFrame
columns and values that are tuples containing the Axes
instances on which the boxplots are drawn and the actual elements of the boxplots in a dictionary. I think the code is pretty self-explanatory:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import PathPatch
df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])
df['models'] = pd.Series(np.repeat(['model1','model2', 'model3', 'model4', 'model5', 'model6', 'model7'], 20))
bp_dict = df.boxplot(
by="models",layout=(4,1),figsize=(6,8),
return_type='both',
patch_artist = True,
)
colors = ['b', 'y', 'm', 'c', 'g', 'b', 'r', 'k', ]
for row_key, (ax,row) in bp_dict.iteritems():
ax.set_xlabel('')
for i,box in enumerate(row['boxes']):
box.set_facecolor(colors[i])
plt.show()
The resulting plot looks like this:
Hope this helps.
Although you name the return of df.boxplot
bp
, it really is a(n) (array of) axes. Inspecting the axes to get the individual parts of a boxplot is cumbersome (but possible).
First, in order to be able to colorize the interior of the boxes you need to turn the boxes to patches, df.boxplot(..., patch_artist=True)
.
Then you would need to find the boxes within all the artists in the axes.
# We want to make the 4th box in the second axes red
axes[1].findobj(matplotlib.patches.Patch)[3].set_facecolor("red")
Complete code:
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
df = pd.DataFrame(np.random.rand(140, 4), columns=['A', 'B', 'C', 'D'])
df['models'] = pd.Series(np.repeat(['model1', 'model2', 'model3', 'model4',
'model5', 'model6', 'model7'], 20))
axes = df.boxplot(by="models", layout=(len(df.columns)-1,1), figsize=(6,8), patch_artist=True)
for ax in axes:
ax.set_xlabel('')
# We want to make the 4th box in the second axes red
axes[1].findobj(matplotlib.patches.Patch)[3].set_facecolor("red")
fig = axes[0].get_figure()
fig.suptitle('New title here')
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With