Bin a DataFrame of floats or datetime strings and plot the histogram

    Arguments:
      df (DataFrame of str or float): table of data containing data to be counted and binned
      column (str): label of the DataFrame column containing data to be counted and binned
      width (float): 0 < width <= 1, the graphical width of the bars as a fraction of the bin width
      resolution (int): 0 < resolution < 7, 
        for a number of timetuple fields to truncate to for binning 
    TODO:
      - allow more than one column/field/series
      - add of cumulative histogram line overlay
      - separate out plotting from counting and datetime conversion

    FIXME:
      - fail for `label_len=7`

def histogram_and_plot(df, column=0, width=0.9, resolution=2, str_timetags=True, counted=False,
                   title='', xlabel=None, datetime_format='%b %d, %Y', num_labels=24, bins=None, 
                   labels=None, color=None, alpha=None, normalize=True, percent=False, padding=0.03,
                   formatter=None, ylabel_precision=2,
                   figsize=None, line_color='#C0C0C0', bg_color='white', bg_alpha=1, tight_layout=True,
                   ylabel=None, grid='on', rotation=-60, ha='left',
                   save_path='plot_histogram', dpi=200):
    """Bin a DataFrame of floats or datetime strings and plot the histogram

    Arguments:
      df (DataFrame of str or float): table of data containing data to be counted and binned
      column (str): label of the DataFrame column containing data to be counted and binned
      width (float): 0 < width <= 1, the graphical width of the bars as a fraction of the bin width
      resolution (int): 0 < resolution < 7, 
        for a number of timetuple fields to truncate to for binning 
    TODO:
      - allow more than one column/field/series
      - add of cumulative histogram line overlay
      - separate out plotting from counting and datetime conversion

    FIXME:
      - fail for `label_len=7`
    """

    try:
        assert len(bins) == len(counted) + 1
        his0, his1 = bins, counted
    except:
        his0, his1 = [], []

        if isinstance(df, basestring) and os.path.isfile(df):
            df = pd.DataFrame.from_csv(df)
        if not isinstance(df, pd.DataFrame):
            df = pd.DataFrame(df)
        if isinstance(column, int):
            column = df.columns[column]
        if not column in df.columns:
            if not column == 'index':
                warnings.warn('Unable to find a column named {0}, so using the index named "{1}" instead. The available columns are:\n{2}'.format(
                    column, df.index.name, df.columns))
            column = df.index.name
        if column == df.index.name:
            df[column] = df.index.values

    if not len(his0) and not len(his1) and not isinstance(df[column].dropna().values[0], (float, int)):
        if all(isinstance(val, (datetime.datetime, datetime.date, datetime.time, pd.Timestamp, pd.np.datetime64)) for val in df[column].dropna().values):
            timetag = df[column].values
        elif str_timetags and all(is_valid_american_date_string(val) for val in df[column].dropna().values):
            timetag = [datetime.datetime.strptime(val, '%m/%d/%Y') if isinstance(val, basestring) else make_datetime(val) for val in df[column]]
        else:
            timetag = [make_datetime(val) for val in df[column].values]

        # r['Returned Ordinal'] = [datetime.datetime.strptime(s, '%m/%d/%Y').date().toordinal() for s in r['Returned']]
        if resolution and bins in (None, 0):
            quantized_date = [quantize_datetime(dt, resolution) for dt in timetag]
            quantized_ordinal = ordinal_float(quantized_date)
            his0, his1 = zip(*sorted(Counter(quantized_ordinal).items()))
            bins = his0
        else:
            days = ordinal_float(df[column].dropna())
            bins = generate_bins(bins, days)
            his1, his0 = pd.np.histogram(days, bins=bins)
            
        resolution = int(resolution or 7)

    if counted in (None, 0, False, []):
        if any(his0) and any(his1):
            labels = prettify_datetimes(['-'.join(str(val) for val in datetime_from_ordinal_float(ordinal).timetuple()[:resolution]) for ordinal in his0], format=datetime_format)
        elif isinstance(df[column].values[0], (float, int)):
            if not any(bins):
                bins = resolution * 10
            bins = generate_bins(bins, df[column].dropna())
            his1, his0 = pd.np.histogram(df[column].dropna(), bins=bins)
            labels = ['{:.3g}'.format(val) for val in his0[:-1]]
            # labels = ['{:.3g}-{.3g}'.format(left, right) for left, right in zip(his[0][:-1], his[0][1:])]
            width = max(width, 0.95)
            padding = 0

    if len(his0) > len(his1):
        his0 = his0[:-1]
    his0 = pd.np.array(his0)
    his1 = pd.np.array(his1)
    if normalize:
        normalize = float(normalize)
        total = float(pd.np.sum(his1))
        his1 = normalize * his1 * 1.0 / total
        if not isinstance(ylabel, basestring):
            if normalize in (1., 100.):
                ylabel = 'Frequency (Probability or Count/Total)'
                if not (formatter and callable(formatter)):
                    formatter = percent_formatter
                    if normalize != 1.:
                        percent_formatter.scale_factor = 1.
                        percent_formatter.precision = ylabel_precision
                        normalize = 1.
            else:
                ylabel = 'Scaled Frequency ({0:.6g}*Count/Total)'.format(normalize)

    return plot_histogram( hist=(his0, his1), width=width,
                           title=title, xlabel=xlabel, datetime_format=datetime_format, num_labels=num_labels,
                           labels=labels, color=color, alpha=alpha, normalize=normalize, percent=percent, padding=padding,
                           formatter=formatter, ylabel_precision=ylabel_precision,
                           figsize=figsize, line_color=line_color, bg_color=bg_color, bg_alpha=bg_alpha, tight_layout=tight_layout,
                           ylabel=ylabel, grid=grid, rotation=rotation, ha=ha,
                           save_path=save_path, dpi=dpi)