from abc import abstractmethod, ABCMeta

import numpy as np
from sklearn.utils.validation import check_array, check_is_fitted

from .utils import construct_pandas_object


class DetectorMixin(metaclass=ABCMeta):
    """Mixin class for all detectors."""

    _estimator_type = 'detector'

    @abstractmethod
    def fit(self, X, y=None, **fit_param):
        """Fit the model according to the given training data."""

        pass

    def fit_predict(self, X, y=None, **fit_param):
        """Fit the model according to the given training data and predict
        labels (0 inlier, 1 outlier) on the training set.

        Parameters
        ----------
        X : array-like, shape = (n_samples, n_features)
            Samples.

        Returns
        -------
        y_pred : array-like, shape = (n_samples) or (n_windows)
            Return 0 for inliers and 1 for outliers.
        """

        return self.fit(X, y, **fit_param).predict(X)

    @construct_pandas_object
    @abstractmethod
    def anomaly_score(self, X):
        """Compute anomaly scores."""

        pass

    @construct_pandas_object
    def predict(self, X):
        """Predict if a particular sample is an outlier or not.

        Parameters
        ----------
        X : array-like, shape = (n_samples, n_features)
            Test samples.

        Returns
        -------
        y_pred : array-like, shape = (n_samples) or (n_windows)
            Return 0 for inliers and 1 for outliers.
        """

        check_is_fitted(self, ['threshold_'])

        X = check_array(X)

        if isinstance(self.threshold_, float):
            return (
                self.anomaly_score(X) > self.threshold_
            ).astype(np.int32)

        else:
            return np.any(
                self.anomaly_score(X) > self.threshold_, axis=1
            ).astype(np.int32)

@@ -53,16 +53,48 @@
 y as np%0A
+import matplotlib.pyplot as plt%0A
 from skl
@@ -152,16 +152,17 @@
 fitted%0A%0A
+%0A
 from .ut
@@ -833,39 +833,25 @@
 = (n_samples
-) or (n_windows
+,
 )%0A          
@@ -1419,23 +1419,9 @@
 ples
-) or (n_windows
+,
 )%0A  
@@ -1543,197 +1543,1255 @@
     
-X = check_array(X)%0A%0A        if isinstance(self.threshold_, float):%0A            return (%0A                self.a
+return (self.anomaly_score(X) %3E self.threshold_).astype(np.int32)%0A%0A    def plot_anomaly_score(%0A        self,             X,%0A        ax=None,          title=None,%0A        xlim=None,        ylim=None,%0A        xlabel='Samples', ylabel='Anomaly score',%0A        grid=True,        **kwargs%0A    ):%0A        %22%22%22Plot anomaly scores.%0A%0A        Parameters%0A        ----------%0A        X : array-like, shape = (n_samples, n_features)%0A            Test samples.%0A%0A        ax : matplotlib Axes, default None%0A            Target axes instance.%0A%0A        title : string, default None%0A            Axes title. To disable, pass None.%0A%0A        xlim : tuple, default None%0A            Tuple passed to axes.xlim().%0A%0A        ylim : tuple, default None%0A            Tuple passed to axes.ylim().%0A%0A        xlabel : string, default %22Samples%22%0A            X axis title label. To disable, pass None.%0A%0A        ylabel : string, default %22A
 nomaly
-_
+ 
 score
-(X) %3E self.threshold_%0A            ).astype(np.int32)%0A%0A        else:
+%22%0A            Y axis title label. To disable, pass None.%0A%0A        grid : boolean, default True%0A            If True, turn the axes grids on.%0A%0A        **kwargs : dictionary%0A            Other keywords passed to ax.bar().%0A%0A        Returns%0A        -------%0A        ax : matplotlib Axes%0A        %22%22%22%0A%0A        check_is_fitted(self, %5B'threshold_'%5D)%0A
 %0A   
@@ -2799,26 +2799,113 @@
     
+X
     
-return np.any(
+        = check_array(X)%0A        n_samples, _ = X.shape%0A%0A        xlocs        = np.arange(n_samples)
 %0A   
@@ -2909,23 +2909,30 @@
         
+scores
        
+=
  self.an
@@ -2949,62 +2949,704 @@
 e(X)
- %3E self.threshold_, axis=1%0A            ).astype(np.int32)
+%0A%0A        if ax is None:%0A            _, ax    = plt.subplots(1, 1)%0A%0A        if xlim is None:%0A            xlim     = (-1, n_samples)%0A%0A        if ylim is None:%0A            ylim     = (0, 1.1 * max(max(scores), self.threshold_))%0A%0A        if title is not None:%0A            ax.set_title(title)%0A%0A        if xlabel is not None:%0A            ax.set_xlabel(xlabel)%0A%0A        if ylabel is not None:%0A            ax.set_ylabel(ylabel)%0A%0A        ax.set_xlim(xlim)%0A        ax.set_ylim(ylim)%0A        ax.grid(grid)%0A%0A        ax.bar(%0A            left     = xlocs,%0A            height   = scores,%0A            align    = 'center',%0A            **kwargs%0A        )%0A%0A        ax.hlines(self.threshold_, *xlim)%0A%0A        return ax
 %0A

add plot_anomaly_score method