Ejemplo 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
Ejemplo n.º 2
0
def plot_interactions(locations: List[str],
                      latent_graph: ndarray,
                      map: Basemap,
                      ax: Axis,
                      skip_first: bool = False):
    """
    Given station ids and latent graph plot edges in different colors
    """

    # Transform lan/lot into region-specific values
    pixel_coords = [map(*coords) for coords in locations]

    # Draw contours and borders
    map.shadedrelief()
    map.drawcountries()
    # m.bluemarble()
    # m.etopo()


    # Plot Locations of weather stations
    for i, (x, y) in enumerate(pixel_coords):
        ax.plot(x, y, 'ok', markersize=10, color='yellow')
        ax.text(x + 10, y + 10, "Station " + str(i), fontsize=20, color='yellow');

    # Infer number of edge types and atoms from latent graph
    n_atoms = latent_graph.shape[-1]
    n_edge_types = latent_graph.shape[0]

    color_map = get_cmap('Set1')

    for i in range(n_atoms):
        for j in range(n_atoms):
            for edge_type in range(n_edge_types):
                if latent_graph[edge_type, i, j] > 0.5:

                    if skip_first and edge_type == 0:
                        continue

                    # Draw line between points
                    x = locations[i]
                    y = locations[j]
                    map.drawgreatcircle(x[0], x[1], y[0], y[1],
                                        color=color_map(edge_type - 1),
                                        label=str(edge_type))
    handles, labels = ax.get_legend_handles_labels()
    unique = [(h, l) for i, (h, l) in enumerate(zip(handles, labels)) if l not in labels[:i]]
    ax.legend(*zip(*unique))
    return ax
Ejemplo n.º 3
0
    def add_to_plot(self,
                    ax: Axis,
                    N: int = 201,
                    xrange: Tuple[float] = None,
                    xscale: float = 1,
                    yscale: float = 1,
                    **kwargs):
        """Add fit to existing plot axis

        Args:
            ax: Axis to add plot to
            N: number of points to use as x values (to smoothe fit curve)
            xrange: Optional range for x values (min, max)
            xscale: value to multiple x values by to rescale axis
            yscale: value to multiple y values by to rescale axis
            kwargs: Additional plot kwargs. By default Fit.plot_kwargs are used

        Returns:
            plot_handle of fit curve
        """
        if xrange is None:
            x_vals = self.xvals
            x_vals_full = np.linspace(min(x_vals), max(x_vals), N)
        else:
            x_vals_full = np.linspace(*xrange, N)

        y_vals_full = self.fit_result.eval(
            **{self.sweep_parameter: x_vals_full})
        x_vals_full *= xscale
        y_vals_full *= yscale
        plot_kwargs = {**self.plot_kwargs, **kwargs}
        self.plot_handle, = ax.plot(x_vals_full, y_vals_full, **plot_kwargs)
        return self.plot_handle
Ejemplo n.º 4
0
    def add_to_plot(self,
                    ax: Axis,
                    N: int = 201,
                    xrange: Tuple[float] = None,
                    xscale: float = 1,
                    yscale: float = 1,
                    **kwargs):
        """Add fit to existing plot axis

        Args:
            ax: Axis to add plot to
            N: number of points to use as x values (to smoothe fit curve)
            xrange: Optional range for x values (min, max)
            xscale: value to multiple x values by to rescale axis
            yscale: value to multiple y values by to rescale axis
            kwargs: Additional plot kwargs. By default Fit.plot_kwargs are used

        Returns:
            plot_handle of fit curve
        """
        if xrange is None:
            x_vals = self.xvals
            x_vals_full = np.linspace(min(x_vals), max(x_vals), N)
        else:
            x_vals_full = np.linspace(*xrange, N)

        y_vals_full = self.fit_result.eval(
            **{self.sweep_parameter: x_vals_full})
        x_vals_full *= xscale
        y_vals_full *= yscale

        # Set default plot kwargs while de-aliasing (e.g. 'lw' -> 'linewidth')
        # kwargs to prevent duplicate keys
        kwargs = {
            **self.default_plot_kwargs,
            **cbook.normalize_kwargs(kwargs, mlines.Line2D)
        }
        self.plot_handle, = ax.plot(x_vals_full, y_vals_full, **kwargs)
        return self.plot_handle
Ejemplo n.º 5
0
def control_plot(data: (List[int], List[float], pd.Series, np.array),
                 upper_control_limit: (int, float),
                 lower_control_limit: (int, float),
                 highlight_beyond_limits: bool = True,
                 highlight_zone_a: bool = True,
                 highlight_zone_b: bool = True,
                 highlight_zone_c: bool = True,
                 highlight_trend: bool = True,
                 highlight_mixture: bool = True,
                 highlight_stratification: bool = True,
                 highlight_overcontrol: bool = True,
                 ax: Axis = None):
    """
    Create a control plot based on the input data.

    :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 highlight_beyond_limits: True if points beyond limits are to be highlighted
    :param highlight_zone_a: True if points that are zone A violations are to be highlighted
    :param highlight_zone_b: True if points that are zone B violations are to be highlighted
    :param highlight_zone_c: True if points that are zone C violations are to be highlighted
    :param highlight_trend: True if points that are trend violations are to be highlighted
    :param highlight_mixture: True if points that are mixture violations are to be highlighted
    :param highlight_stratification: True if points that are stratification violations are to be highlighted
    :param highlight_overcontrol: True if points that are overcontrol violations are to be hightlighted
    :param ax: an instance of matplotlib.axis.Axis
    :return: None
    """

    data = coerce(data)

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

    ax.plot(data)
    ax.set_title('Zone Control Chart')

    spec_range = (upper_control_limit - lower_control_limit) / 2
    spec_center = lower_control_limit + spec_range
    zone_c_upper_limit = spec_center + spec_range / 3
    zone_c_lower_limit = spec_center - spec_range / 3
    zone_b_upper_limit = spec_center + 2 * spec_range / 3
    zone_b_lower_limit = spec_center - 2 * spec_range / 3
    zone_a_upper_limit = spec_center + spec_range
    zone_a_lower_limit = spec_center - spec_range

    ax.axhline(spec_center, linestyle='--', color='red', alpha=0.6)
    ax.axhline(zone_c_upper_limit, linestyle='--', color='red', alpha=0.5)
    ax.axhline(zone_c_lower_limit, linestyle='--', color='red', alpha=0.5)
    ax.axhline(zone_b_upper_limit, linestyle='--', color='red', alpha=0.3)
    ax.axhline(zone_b_lower_limit, linestyle='--', color='red', alpha=0.3)
    ax.axhline(zone_a_upper_limit, linestyle='--', color='red', alpha=0.2)
    ax.axhline(zone_a_lower_limit, linestyle='--', color='red', alpha=0.2)

    left, right = ax.get_xlim()
    right_plus = (right - left) * 0.01 + right

    ax.text(right_plus, upper_control_limit, s='UCL', va='center')
    ax.text(right_plus, lower_control_limit, s='LCL', va='center')

    ax.text(right_plus, (spec_center + zone_c_upper_limit) / 2,
            s='Zone C',
            va='center')
    ax.text(right_plus, (spec_center + zone_c_lower_limit) / 2,
            s='Zone C',
            va='center')
    ax.text(right_plus, (zone_b_upper_limit + zone_c_upper_limit) / 2,
            s='Zone B',
            va='center')
    ax.text(right_plus, (zone_b_lower_limit + zone_c_lower_limit) / 2,
            s='Zone B',
            va='center')
    ax.text(right_plus, (zone_a_upper_limit + zone_b_upper_limit) / 2,
            s='Zone A',
            va='center')
    ax.text(right_plus, (zone_a_lower_limit + zone_b_lower_limit) / 2,
            s='Zone A',
            va='center')

    plot_params = {'alpha': 0.3, 'zorder': -10, 'markersize': 14}

    if highlight_beyond_limits:
        beyond_limits_violations = control_beyond_limits(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(beyond_limits_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(beyond_limits_violations,
                    'o',
                    color='red',
                    label='beyond limits',
                    **plot_params)

    if highlight_zone_a:
        zone_a_violations = control_zone_a(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(zone_a_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_a_violations,
                    'o',
                    color='orange',
                    label='zone a violations',
                    **plot_params)

    if highlight_zone_b:
        zone_b_violations = control_zone_b(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(zone_b_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_b_violations,
                    'o',
                    color='blue',
                    label='zone b violations',
                    **plot_params)

    if highlight_zone_c:
        zone_c_violations = control_zone_c(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(zone_c_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_c_violations,
                    'o',
                    color='green',
                    label='zone c violations',
                    **plot_params)

    if highlight_trend:
        zone_trend_violations = control_zone_trend(data=data)
        if len(zone_trend_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_trend_violations,
                    'o',
                    color='purple',
                    label='trend violations',
                    **plot_params)

    if highlight_mixture:
        zone_mixture_violations = control_zone_mixture(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(zone_mixture_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_mixture_violations,
                    'o',
                    color='brown',
                    label='mixture violations',
                    **plot_params)

    if highlight_stratification:
        zone_stratification_violations = control_zone_stratification(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(zone_stratification_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_stratification_violations,
                    'o',
                    color='orange',
                    label='stratification violations',
                    **plot_params)

    if highlight_overcontrol:
        zone_overcontrol_violations = control_zone_overcontrol(
            data=data,
            upper_control_limit=upper_control_limit,
            lower_control_limit=lower_control_limit)
        if len(zone_overcontrol_violations):
            plot_params['zorder'] -= 1
            plot_params['markersize'] -= 1
            ax.plot(zone_overcontrol_violations,
                    'o',
                    color='blue',
                    label='overcontrol violations',
                    **plot_params)

    ax.legend()
Ejemplo n.º 6
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')