Skip to content

Visualization

Visualization utilities for RUL estimation models

It is possible to visualize how it grows the unexploited lifetime grows as the conservative window size grows and how the unexpected breaks decrease as the conservative window size grows.

barplot_errors_wrt_RUL(results_dict, nbins, y_axis_label=None, x_axis_label=None, ax=None, color_palette='hls', **kwargs)

Barlots of difference between true and predicted RUL

Parameters:

Name Type Description Default
results_dict Dict[str, List[PredictionResult]]

Dictionary with the results for each model

required
nbins int

Number of bins in wich divide the RUL target

required
y_axis_label

Y label

None
x_axis_label

X label

None
ax

Axis

None
color_palette str
'hls'
Source code in ceruleo/graphics/results.py
def barplot_errors_wrt_RUL(
    results_dict: Dict[str, List[PredictionResult]],
    nbins: int,
    y_axis_label=None,
    x_axis_label=None,
    ax=None,
    color_palette: str = "hls",
    **kwargs,
):
    """
    Barlots of difference between true and predicted RUL

    Parameters:
        results_dict: Dictionary with the results for each model
        nbins: Number of bins in wich divide the RUL target
        y_axis_label: Y label
        x_axis_label: X label
        ax: Axis
        color_palette: 

    """
    if ax is None:
        fig, ax = plt.subplots(**kwargs)
    bin_edges, model_results = models_cv_results(results_dict, nbins)
    return _cv_barplot_errors_wrt_RUL_multiple_models(
        bin_edges,
        model_results,
        ax=ax,
        y_axis_label=y_axis_label,
        x_axis_label=x_axis_label,
        color_palette=color_palette,
    )

boxplot_errors_wrt_RUL(results_dict, nbins, y_axis_label=None, x_axis_label=None, ax=None, **kwargs)

Boxplots of difference between true and predicted RUL over Cross-validated results

Parameters:

Name Type Description Default
results_dict Dict[str, List[PredictionResult]]

Dictionary with the results of the fitted models

required
nbins int

Number of bins to divide the

required
y_axis_label Optional[str]

Optional string to be added to the y axis

None
x_axis_label Optional[str]

Optional string to be added to the x axis

None
ax

Optional axis in which the plot will be drawed. If an axis is not provided, it will create one.

None
Return

The axis in which the plot has been made

Source code in ceruleo/graphics/results.py
def boxplot_errors_wrt_RUL(
    results_dict: Dict[str, List[PredictionResult]],
    nbins: int,
    y_axis_label: Optional[str] = None,
    x_axis_label: Optional[str] = None,
    ax=None,
    **kwargs,
) -> matplotlib.axes.Axes:
    """
    Boxplots of difference between true and predicted RUL over Cross-validated results


    Parameters:
        results_dict: Dictionary with the results of the fitted models
        nbins: Number of bins to divide the
        y_axis_label: Optional string to be added to the y axis
        x_axis_label: Optional string to be added to the x axis
        ax: Optional axis in which the plot will be drawed.
            If an axis is not provided, it will create one.

    Keyword arguments:
        **kwargs

    Return:
        The axis in which the plot has been made
    """
    if ax is None:
        fig, ax = plt.subplots(**kwargs)
    else:
        fig = ax.figure

    bin_edges, model_results = models_cv_results(results_dict, nbins)
    return _boxplot_errors_wrt_RUL_multiple_models(
        bin_edges,
        model_results,
        fig=fig,
        ax=ax,
        y_axis_label=y_axis_label,
        x_axis_label=x_axis_label,
    )

cv_plot_errors_wrt_RUL(bin_edges, error_histogram, **kwargs)

Source code in ceruleo/graphics/results.py
def cv_plot_errors_wrt_RUL(bin_edges, error_histogram, **kwargs):
    """"""
    fig, ax = plt.subplots(**kwargs)
    labels = []
    heights = []
    xs = []
    yerr = []

    for i in range(len(error_histogram)):
        xs.append(i)
        heights.append(np.mean(error_histogram[i]))
        yerr.append(np.std(error_histogram[i]))
        labels.append(f"[{bin_edges[i]:.1f}, {bin_edges[i+1]:.1f})")

    ax.bar(height=heights, x=xs, yerr=yerr, tick_label=labels)
    ax.set_xlabel("RUL")
    ax.set_ylabel("RMSE")

    return ax

plot_life(life, ax=None, units='', markersize=0.7, add_fitted=False, plot_target=True, add_regressed=True, start_x=0, label='', **kwargs)

Plot a single life

Parameters:

Name Type Description Default
life FittedLife

A fitted life

required
ax Optional[Axes]

The axis where to plot

None
units

Optional[str], optional description, by default ""

''
markersize float

Size of the marker

0.7
add_fitted bool

Wether to add the LS fitted line to the points

False
plot_target bool

Wether to plot the true RUL values

True
add_regressed bool
True
start_x int

Initial point of the time-indepedent feature to plot

0
label str
''

Returns:

Type Description
Axes

The plot axis

Source code in ceruleo/graphics/results.py
def plot_life(
    life: FittedLife,
    ax: Optional[matplotlib.axes.Axes]=None,
    units: Optional[str] = "",
    markersize: float = 0.7,
    add_fitted: bool = False,
    plot_target: bool = True,
    add_regressed: bool = True,
    start_x:int= 0,
    label:str = '',
    **kwargs,
) -> matplotlib.axes.Axes:
    """
    Plot a single life

    Parameters:
        life: A fitted life
        ax: The axis where to plot
        units : Optional[str], optional
            _description_, by default ""
        markersize: Size of the marker
        add_fitted: Wether to add the LS fitted line to the points
        plot_target: Wether to plot the true RUL values
        add_regressed:
        start_x: Initial point of the time-indepedent feature to plot
        label: 

    Returns:
        The plot axis
    """
    if ax is None:
        _, ax = plt.subplots(1, 1, **kwargs)

    time = life.time

    ax.plot(
        life.time[start_x: len(life.y_pred)],
        life.y_pred[start_x:],
        "o",
        label=f"Predicted {label}",
        markersize=markersize,
    )
    if plot_target:
        ax.plot(life.time, life.y_true, label="True", linewidth=3)
    if add_regressed and life.y_true[-1] > 0:
            time1 = np.hstack((time[-1], time[-1] + life.y_true[-1]))
            ax.plot(time1, [life.y_true[-1], 0], label="Regressed true")
    if add_fitted:
        #time1 = np.hstack(
        #    (time[len(life.y_pred) - 1], time[len(life.y_pred) - 1] + life.y_pred[-1])
        #)
        #ax.plot(time1, [life.y_pred[-1], 0], label="Projected end")
        ax.plot(
           life.time,
           life.y_pred_fitted,
           label="Picewise fitted",
        )
        ax.plot(
           life.time,
           life.y_true_fitted,
           label="Picewise fitted",
        )

    ax.set_ylabel(units)
    ax.set_xlabel(units)
    _, max = ax.get_ylim()
    ax.set_ylim(0 - max / 10, max)
    legend = ax.legend(markerscale=15,)



    return ax

plot_lives(ds)

Plot each life

Parameters:

Name Type Description Default
ds TransformedDataset

A transformed dataset

required
Source code in ceruleo/graphics/results.py
def plot_lives(ds: TransformedDataset):
    """
    Plot each life

    Parameters:
        ds: A transformed dataset
    """
    fig, ax = plt.subplots()
    it = ds
    for _, y in it:
        ax.plot(y)
    return ax

plot_predictions(result, *, ax=None, units='Hours [h]', markersize=0.7, marker='o', plot_fitted=True, model_name='', **kwargs)

Plots the predicted and the true remaining useful lives

Parameters:

Name Type Description Default
result Union[PredictionResult, Tuple[ndarray, ndarray]]

A PredictionResult object or a tuple with (y_true, y_predicted)

required
ax Optional[Axes]

Axis to plot. If it is missing a new figure will be created

None
units str

Units of time to be used in the axis labels

'Hours [h]'
marker str

Marker type

'o'
markersize float

The size of the marker

0.7
plot_fitted bool

Wether to plot a LS line

True
model_name str

Name of the model

''

Returns:

Type Description
Axes

The axis on which the plot has been made

Source code in ceruleo/graphics/results.py
def plot_predictions(
    result: Union[PredictionResult, Tuple[np.ndarray, np.ndarray]],
    *,
    ax:Optional[matplotlib.axes.Axes]=None,
    units: str = "Hours [h]",
    markersize: float = 0.7,
    marker: str = 'o',
    plot_fitted: bool  = True,
    model_name:str = '',
    **kwargs,
) -> matplotlib.axes.Axes:
    """
    Plots the predicted and the true remaining useful lives

    Parameters:
        result: A PredictionResult object or a tuple with (y_true, y_predicted)
        ax:  Axis to plot. If it is missing a new figure will be created
        units: Units of time to be used in the axis labels
        marker: Marker type
        markersize: The size of the marker
        plot_fitted: Wether to plot a LS line
        model_name: Name of the model


    Returns:
        The axis on which the plot has been made
    """
    if ax is None:
        _, ax = plt.subplots(1, 1, **kwargs)


    if isinstance(result, PredictionResult):
        y_predicted = result.predicted_RUL
        y_true = result.true_RUL
    else:
        y_true, y_predicted = result
    ax.plot(y_predicted, marker, label=f"Predicted {model_name}", markersize=markersize)
    ax.plot(y_true, label="True")
    x = 0


    if plot_fitted:
        try:
            fitted = np.hstack([life.y_pred_fitted for life in split_lives(result)])
            ax.plot(fitted, label='Fitted')

        except:

            pass
    ax.set_ylabel(units)
    ax.set_xlabel(units)
    legend = ax.legend()
    for l in legend.legend_handles:
        l.set_markersize(6)


    return ax

plot_predictions_grid(results, ncols=3, alpha=1.0, xlabel=None, ylabel=None, **kwargs)

Plot a matrix of predictions

Parameters:

Name Type Description Default
results Union[PredictionResult, List[PredictionResult]]

Dictionary with the results

required
ncols int

Number of colmns in the plot

3
alpha float

Opacity of the predicted curves

1.0
xlabel Optional[str]

Xlabel

None
ylabel Optional[str]

YLabel

None
Return

The axis on which the plot has been made

Source code in ceruleo/graphics/results.py
def plot_predictions_grid(
    results: Union[PredictionResult, List[PredictionResult]],
    ncols: int = 3,
    alpha: float =1.0,
    xlabel: Optional[str] = None,
    ylabel: Optional[str] = None,
    **kwargs,
):
    """
    Plot a matrix of predictions

    Parameters:
        results: Dictionary with the results
        ncols: Number of colmns in the plot
        alpha: Opacity of the predicted curves
        xlabel: Xlabel
        ylabel: YLabel

    Return:
        The axis on which the plot has been made
    """

    def linear_to_subindices(i, ncols):
        row = int(i / ncols)
        col = i % ncols
        return row, col

    if isinstance(results, PredictionResult):
        results = [results]

    init = False

    for model_results in results:
        lives_model = split_lives(model_results)
        NROW = math.ceil(len(lives_model) / ncols)
        if not init:
            fig, ax = plt.subplots(NROW, ncols, squeeze=False, **kwargs)

        for i, life in enumerate(lives_model):
            row, col = linear_to_subindices(i, ncols)

            if not init:
                ax[row, col].plot(life.time, life.y_true, label="True")

            ax[row, col].plot(
                life.time, life.y_pred, label=model_results.name, alpha=alpha
            )
            if xlabel is not None:
                ax[row, col].set_xlabel(xlabel)
            if ylabel is not None:
                ax[row, col].set_ylabel(ylabel)
        init = True
    for j in range(len(lives_model), NROW * ncols):
        row, col = linear_to_subindices(j, ncols)
        fig.delaxes(ax[row, col])

    for a in ax.flatten():
        a.legend()
    return ax

plot_unexpected_breaks(results_dict, max_window, n, ax=None, units='', add_shade=True, **kwargs)

Plot the risk of unexpected breaks with respect to the maintenance window

Parameters:

Name Type Description Default
results_dict dict

Dictionary with the results

required
max_window int

Maximum size of the maintenance windows

required
n int

Number of points used to evaluate the window size

required
ax Optional[Axes]

axis on which to draw, by default None

None
units Optional[str]

Units to use in the xlabel, by default ""

''

Returns:

Type Description
Axes

The axis in which the plot was made

Source code in ceruleo/graphics/results.py
def plot_unexpected_breaks(
    results_dict: dict,
    max_window: int,
    n: int,
    ax: Optional[matplotlib.axes.Axes] = None,
    units: Optional[str] = "",
    add_shade: bool = True,
    **kwargs,
) -> matplotlib.axes.Axes:
    """
    Plot the risk of unexpected breaks with respect to the maintenance window

    Parameters:
        results_dict: Dictionary with the results
        max_window: Maximum size of the maintenance windows
        n: Number of points used to evaluate the window size
        ax: axis on which to draw, by default None
        units: Units to use in the xlabel, by default ""

    Returns:
        The axis in which the plot was made
    """
    if ax is None:
        fig, ax = plt.subplots(**kwargs)
    n_models = len(results_dict)
    colors = sns.color_palette("hls", n_models)
    for i, model_name in enumerate(results_dict.keys()):
        m, mean_ub, std_ub = unexpected_breaks(results_dict[model_name], max_window, n)
        ax.plot(m, mean_ub, label=model_name, color=colors[i])
        if add_shade:
            ax.fill_between(m, mean_ub+std_ub, mean_ub-std_ub, alpha=0.1, color=colors[i])

    ax.set_title("Unexpected breaks")
    ax.set_xlabel("Fault window size" + units)
    ax.set_ylabel("Risk of breakage")
    ax.legend()
    return ax

shadedline_plot_errors_wrt_RUL(results_dict, nbins, y_axis_label=None, x_axis_label=None, ax=None, **kwargs)

Shaded line

Parameters:

Name Type Description Default
results_dict dict

Dictionary with the results for the model

required
nbins int

Number of bins

required
y_axis_label Optional[str]

Y label

None
x_axis_label Optional[str]

X label

None
ax Optional[Axes]

Plot axis

None

Returns:

Type Description
Axes

The plot axis

Source code in ceruleo/graphics/results.py
def shadedline_plot_errors_wrt_RUL(
    results_dict: dict,
    nbins: int,
    y_axis_label: Optional[str] =None,
    x_axis_label: Optional[str] =None,
    ax: Optional[matplotlib.axes.Axes] =None,
    **kwargs,
) -> matplotlib.axes.Axes:
    """
    Shaded line

    Parameters:
        results_dict: Dictionary with the results for the model
        nbins: Number of bins
        y_axis_label: Y label
        x_axis_label: X label
        ax: Plot axis 

    Returns:
        The plot axis
    """

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

    bin_edges, model_results = models_cv_results(results_dict, nbins)
    return _cv_shadedline_plot_errors_wrt_RUL_multiple_models(
        bin_edges,
        model_results,
        ax=ax,
        bins=nbins,
        y_axis_label=y_axis_label,
        x_axis_label=x_axis_label,
    )