How to pass weights to a Seaborn FacetGrid
Question: I have a set of data that I'm trying to plot using a FacetGrid in seaborn.
Each data point has a weight associated with it, and I want to plot a weighted
histogram in each of the facets of the grid.

For example, say I had the following (randomly created) data set:

    
    
    import seaborn as sns
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    d = pd.DataFrame(np.array([np.random.randint(0, 6, 5000), 
                               np.random.normal(0, 1., 5000),
                               np.random.uniform(0, 1, 5000)]).T, 
                     columns=('cat', 'val', 'weight'))
    

This data is structured like this:

    
    
       cat       val    weight
    0    0 -0.844542  0.668081
    1    0 -0.521177  0.521396
    2    1 -1.160358  0.788465
    3    0 -0.394765  0.115242
    4    5  0.735328  0.003495
    

Normally, if I didn't have weights, I would plot it like this:

    
    
    fg = sns.FacetGrid(d, col='cat', col_wrap=3)
    fg.map(plt.hist, 'val')
    

This makes a grid of histograms where each histogram shows the distribution of
the variable `val` for one value of the category `cat`.

What I would like to do is to weight each of the histograms. If I were making
a single histogram with Matplotlib, I would do this:

    
    
    plt.hist(d.val, weights=d.weight)
    

I tried passing the weights argument to `FacetGrid.map`, but it raises an
error due to the way seaborn slices the data internally to make the grid:

    
    
    fg.map(plt.hist, 'val', weights=d.weight)
    
    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    <ipython-input-33-1403d26cff86> in <module>()
          9 
         10 fg = sns.FacetGrid(d, col='cat', col_wrap=3)
    ---> 11 fg.map(plt.hist, 'val', weights=d.weight)
    
    /opt/conda/lib/python3.4/site-packages/seaborn/axisgrid.py in map(self, func, *args, **kwargs)
        443 
        444             # Draw the plot
    --> 445             self._facet_plot(func, ax, plot_args, kwargs)
        446 
        447         # Finalize the annotations and layout
    
    /opt/conda/lib/python3.4/site-packages/seaborn/axisgrid.py in _facet_plot(self, func, ax, plot_args, plot_kwargs)
        527 
        528         # Draw the plot
    --> 529         func(*plot_args, **plot_kwargs)
        530 
        531         # Sort out the supporting information
    
    /opt/conda/lib/python3.4/site-packages/matplotlib/pyplot.py in hist(x, bins, range, normed, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, hold, **kwargs)
       2894                       histtype=histtype, align=align, orientation=orientation,
       2895                       rwidth=rwidth, log=log, color=color, label=label,
    -> 2896                       stacked=stacked, **kwargs)
       2897         draw_if_interactive()
       2898     finally:
    
    /opt/conda/lib/python3.4/site-packages/matplotlib/axes/_axes.py in hist(self, x, bins, range, normed, weights, cumulative, bottom, histtype, align, orientation, rwidth, log, color, label, stacked, **kwargs)
       5647                 if len(w[i]) != len(x[i]):
       5648                     raise ValueError(
    -> 5649                         'weights should have the same shape as x')
       5650         else:
       5651             w = [None]*nx
    
    ValueError: weights should have the same shape as x
    

So, is there any way to make a plot like this?


Answer: You'll need to write a little wrapper function around `plt.hist` that accepts
a vector of weights as a positional argument. Something like

    
    
    def weighted_hist(x, weights, **kwargs):
        plt.hist(x, weights=weights, **kwargs)
    
    g = sns.FacetGrid(df, ...)
    g.map(weighted_hist, "x_var", "weight_var")
    g.set_axis_labels("x_var", "count")
    

