Exemplo n.º 1
0
def plot_heated_stacked_area(df: pd.DataFrame,
                             lines: str,
                             heat: str,
                             backtest: str = None,
                             reset_y_lim: bool = False,
                             figsize: Tuple[int, int] = (16, 9),
                             color_map: str = 'afmhot',
                             ax: Axis = None,
                             upper_lower_missing_scale: float = 0.05) -> Axis:
    color_function = plt.get_cmap(color_map)
    x = df.index
    y = df[lines].values
    c = df[heat].values
    b = df[backtest].values if backtest is not None else None

    # assert enough data
    assert len(y.shape) > 1 and len(
        c.shape) > 1, "lines and heat need to be 2 dimensions!"

    # make sure we have one more line as heats
    if c.shape[1] == y.shape[1] + 1:
        lower = np.full((c.shape[0], 1),
                        y.min() * (1 - upper_lower_missing_scale))
        upper = np.full((c.shape[0], 1),
                        y.max() * (1 + upper_lower_missing_scale))
        y = np.hstack([lower, y, upper])

    # check for matching columns
    assert y.shape[1] - 1 == c.shape[
        1], f'unexpeced shapes: {y.shape[1] - 1} != {c.shape[1]}'

    _, ax = plt.subplots(figsize=figsize) if ax is None else (None, ax)

    ax.plot(x, y, color='k', alpha=0.0)

    for ci in range(c.shape[1]):
        for xi in range(len(x)):
            ax.fill_between(x[xi - 1:xi + 1],
                            y[xi - 1:xi + 1, ci],
                            y[xi - 1:xi + 1, ci + 1],
                            facecolors=color_function(c[xi - 1:xi + 1, ci]))

        if ci > 0:
            # todo annotate all first last and only convert date if it is actually a date
            ax.annotate(f'{y[-1, ci]:.2f}',
                        xy=(mdates.date2num(x[-1]), y[-1, ci]),
                        xytext=(4, -4),
                        textcoords='offset pixels')

    # reset limits
    ax.autoscale(tight=True)
    if reset_y_lim:
        ax.set_ylim(bottom=y[:, 1].min(), top=y[:, -1].max())

    # backtest
    if backtest:
        ax.plot(x, b)

    return ax
Exemplo n.º 2
0
def ppk_plot(data: (List[int], List[float], pd.Series, np.array),
             upper_control_limit: (int, float),
             lower_control_limit: (int, float),
             threshold_percent: float = 0.001,
             ax: Axis = None):
    """
    Shows the statistical distribution of the data along with CPK and limits.

    :param data: a list, pandas.Series, or numpy.array representing the data set
    :param upper_control_limit: an integer or float which represents the upper control limit, commonly called the UCL
    :param lower_control_limit: an integer or float which represents the upper control limit, commonly called the UCL
    :param threshold_percent: the threshold at which % of units above/below the number will display on the plot
    :param ax: an instance of matplotlig.axis.Axis
    :return: None
    """

    data = coerce(data)
    mean = data.mean()
    std = data.std()

    if ax is None:
        fig, ax = plt.subplots()

    ax.hist(data, density=True, label='data', alpha=0.3)
    x = np.linspace(mean - 4 * std, mean + 4 * std, 100)
    pdf = stats.norm.pdf(x, mean, std)
    ax.plot(x, pdf, label='normal fit', alpha=0.7)

    bottom, top = ax.get_ylim()

    ax.axvline(mean, linestyle='--')
    ax.text(mean, top * 1.01, s='$\mu$', ha='center')

    ax.axvline(mean + std, alpha=0.6, linestyle='--')
    ax.text(mean + std, top * 1.01, s='$\sigma$', ha='center')

    ax.axvline(mean - std, alpha=0.6, linestyle='--')
    ax.text(mean - std, top * 1.01, s='$-\sigma$', ha='center')

    ax.axvline(mean + 2 * std, alpha=0.4, linestyle='--')
    ax.text(mean + 2 * std, top * 1.01, s='$2\sigma$', ha='center')

    ax.axvline(mean - 2 * std, alpha=0.4, linestyle='--')
    ax.text(mean - 2 * std, top * 1.01, s='-$2\sigma$', ha='center')

    ax.axvline(mean + 3 * std, alpha=0.2, linestyle='--')
    ax.text(mean + 3 * std, top * 1.01, s='$3\sigma$', ha='center')

    ax.axvline(mean - 3 * std, alpha=0.2, linestyle='--')
    ax.text(mean - 3 * std, top * 1.01, s='-$3\sigma$', ha='center')

    ax.fill_between(x,
                    pdf,
                    where=x < lower_control_limit,
                    facecolor='red',
                    alpha=0.5)
    ax.fill_between(x,
                    pdf,
                    where=x > upper_control_limit,
                    facecolor='red',
                    alpha=0.5)

    lower_percent = 100.0 * stats.norm.cdf(lower_control_limit, mean, std)
    lower_percent_text = f'{lower_percent:.02f}% < LCL' if lower_percent > threshold_percent else None

    higher_percent = 100.0 - 100.0 * stats.norm.cdf(upper_control_limit, mean,
                                                    std)
    higher_percent_text = f'{higher_percent:.02f}% > UCL' if higher_percent > threshold_percent else None

    left, right = ax.get_xlim()
    bottom, top = ax.get_ylim()
    cpk = calc_ppk(data,
                   upper_control_limit=upper_control_limit,
                   lower_control_limit=lower_control_limit)

    lower_sigma_level = (mean - lower_control_limit) / std
    if lower_sigma_level < 6.0:
        ax.axvline(lower_control_limit,
                   color='red',
                   alpha=0.25,
                   label='limits')
        ax.text(lower_control_limit,
                top * 0.95,
                s=f'$-{lower_sigma_level:.01f}\sigma$',
                ha='center')
    else:
        ax.text(left, top * 0.95, s=f'limit > $-6\sigma$', ha='left')

    upper_sigma_level = (upper_control_limit - mean) / std
    if upper_sigma_level < 6.0:
        ax.axvline(upper_control_limit, color='red', alpha=0.25)
        ax.text(upper_control_limit,
                top * 0.95,
                s=f'${upper_sigma_level:.01f}\sigma$',
                ha='center')
    else:
        ax.text(right, top * 0.95, s=f'limit > $6\sigma$', ha='right')

    strings = [f'Ppk = {cpk:.02f}']

    strings.append(f'$\mu = {mean:.3g}$')
    strings.append(f'$\sigma = {std:.3g}$')

    if lower_percent_text:
        strings.append(lower_percent_text)
    if higher_percent_text:
        strings.append(higher_percent_text)

    props = dict(boxstyle='round',
                 facecolor='white',
                 alpha=0.75,
                 edgecolor='grey')
    ax.text(right - (right - left) * 0.05,
            0.85 * top,
            '\n'.join(strings),
            bbox=props,
            ha='right',
            va='top')

    ax.legend(loc='lower right')