Plot discrete PDFs

    >>> df = pd.DataFrame(pd.np.random.randn(99,3), columns=list('ABC'))
    >>> df['Class'] = pd.np.array((pd.np.matrix([1,1,1])*pd.np.matrix(df).T).T > 0)
    >>> len(hist(df, verbosity=0, class_column='Class'))
    3

def hist(table, field=-1, class_column=None,
         title='', verbosity=2, **kwargs):
    """Plot discrete PDFs

    >>> df = pd.DataFrame(pd.np.random.randn(99,3), columns=list('ABC'))
    >>> df['Class'] = pd.np.array((pd.np.matrix([1,1,1])*pd.np.matrix(df).T).T > 0)
    >>> len(hist(df, verbosity=0, class_column='Class'))
    3
    """
    field = fuzzy_index_match(table, field)
    if not isinstance(table, (pd.DataFrame, basestring)):
        try:
            table = make_dataframe(table.objects.filter(**{field + '__isnull': False}))
        except:
            table = table
    # labels = get_column_labels(table)
    try:
        table = table[pd.notnull(table[field])]
    except:
        pass

    series_labels = []
    if class_column is not None:
        series_labels = sorted(set(table[class_column]))
    labels = [str(c) for c in series_labels] + ['all']

    default_kwargs = {
        'normed': False,
        'histtype': 'bar',
        'color': seaborn.color_palette(),
        'label': labels,
        'log': True,
        'bins': 10,
        }
    default_kwargs.update(kwargs)
    num_colors = len(default_kwargs['color'])
    num_labels = len(default_kwargs['label'])
    default_kwargs['color'] = [default_kwargs['color'][i % num_colors] for i in range(num_labels)]

    if not title:
        title = '{} vs. {}'.format(titlecase(str(field).replace('_', ' ')),
                                   titlecase(str(class_column).replace('_', ' ')))
    if verbosity > 0:
        print('Plotting histogram titled: {}'.format(title))
    if verbosity > 1:
        print('histogram configuration: {}'.format(default_kwargs))
    x = [table[(table[class_column].isnull() if pd.isnull(c) else table[class_column] == c)]
         [field].values for c in series_labels]
    x += [table[field].values]
    if not default_kwargs['normed']:
        default_kwargs['weights'] = [pd.np.ones_like(x_c) / float(len(x_c)) for x_c in x]
    elif isinstance(default_kwargs['normed'], int) and default_kwargs['normed'] < 0:
        default_kwargs['normed'] = 0

    bins = default_kwargs['bins']
    # FIXME: x log scaling doesn't work
    if False and default_kwargs['log'] and isinstance(bins, int):
        max_x = max(pd.np.max(x_c) for x_c in x)
        min_x = min(pd.np.min(x_c) for x_c in x)
        if pd.isnull(min_x) or not(min_x):
            min_x = max_x / 10.
        default_kwargs['bins'] = pd.np.logspace(min_x, max_x, bins)

    fig, ax = plt.subplots()
    ans = plt.hist(x, **default_kwargs)
    # FIXME: x log scaling doesn't work
    if False and default_kwargs['log'] and isinstance(bins, int):
        ax.set_xscale('log')
    if verbosity > 1:
        plt.legend(default_kwargs['label'])
        try:
            plt.show(block=False)
        except:
            plt.show()

    plt.title(title)
    plt.xlabel(titlecase(field.replace('_', ' ')))
    if 'weights' in default_kwargs:
        plt.ylabel('Normalized Frequency or Probability')
    elif default_kwargs['normed']:
        plt.ylabel('Normalized Count')
    else:
        plt.ylabel('Count')
    if verbosity > 2:
        plt.savefig(make_timestamp() + '--' + title.replace(' ', '-') + '.png', transparent=True)
    return ans