'How to customize histogram using seaborn FacetGrid

I am using seaborn's FacetGrid to do multiple histogram plots from a dataframe (plot_df) on the parameter - "xyz". But I want to do the following additional things too in those plots,

  1. Create a vertical axes line at x-value = 0
  2. Color all the bins that are equal to or lesser than 0 (on x-axis) with a different shade
  3. Calculate the percentage area of the histogram for only those bins that are below 0 (on x-axis)

I am able to get lot of examples online but not with seaborn FacetGrid option

g = sns.FacetGrid(plot_df, col='xyz', height=5)```

g.map(plt.hist, "slack", bins=50)

enter image description here



Solution 1:[1]

You could loop through the generated axes (for xyz, ax in g.axes_dict.items(): ....) and call your plotting functions for each of those axes.

Or, you could call g.map_dataframe(...) with a custom function. That function will need to draw onto the "current ax".

Changing the x and y labels, needs to be done after the call to g.map_dataframe() because seaborn erases the x and y labels at the end of that functions.

You can call plt.setp(g.axes, xlabel='data', ylabel='frequency') to set the labels for all the subplots. Or g.set_ylabels('...') to only set the y labels for the "outer" subplots.

Here is some example code to get you started:

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

def individual_plot(**kwargs):
     ax = plt.gca()  # get the current ax
     data = kwargs['data']['slack'].values
     xmin, xmax = data.min(), data.max()
     bin_width = xmax / 50
     # histogram part > 0
     ax.hist(data, bins=np.arange(0.000001, xmax + 0.001, bin_width), color='tomato')
     # histogram part < 0
     ax.hist(data, bins=-np.arange(0, abs(xmin) + bin_width + 0.001, bin_width)[::-1], color='lime')
     # line at x=0
     ax.axvline(0, color='navy', ls='--')
     # calculate and show part < 0
     percent_under_zero = sum(data <= 0) / len(data) * 100
     ax.text(0.5, 0.98, f'part < 0: {percent_under_zero:.1f} %',
             color='k', ha='center', va='top', transform=ax.transAxes)

# first generate some test data
plot_df = pd.DataFrame({'xyz': np.repeat([*'xyz'], 1000),
                        'slack': np.random.randn(3000) * 10 + np.random.choice([10, 500], 3000, p=[0.9, 0.1])})

g = sns.FacetGrid(plot_df, col='xyz', height=5)
g.map_dataframe(individual_plot)
plt.setp(g.axes, xlabel='data', ylabel='frequency')

plt.tight_layout()
plt.show()

sns.FacetGrid with cumstomized plots

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1