Skip to content

Commit

Permalink
Issue #35: Add anomaly detection plot and an example in the notebook (#…
Browse files Browse the repository at this point in the history
…38)

* Issue #35: Add anomaly detection plot and an example in the notebook

* Changed plot_time_series_anomalies function, added a test function, updated changelog

* Reviewed issue and updated files based on feedback.

---------

Co-authored-by: Cigde <[email protected]>
  • Loading branch information
cigdegoktas and Cigde authored Dec 1, 2024
1 parent fe4a447 commit 662bdec
Show file tree
Hide file tree
Showing 8 changed files with 2,811 additions and 31 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
``dtaianomaly`` is maintained by Louis Carpentier (DTAI, KU Leuven).

Other contributors, listed alphabetically, are:
* Cigde Goktas (KU Leuven)
* Nick Seeuws (Leuven.AI, KU Leuven)
1 change: 1 addition & 0 deletions docs/additional_information/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Added
or labels
- Added the property ``__version__`` to ``dtaianomaly``, which can be accessed from code.
- Included the used version of ``dtaianomaly`` when logging errors.
- Added the ``plot_time_series_anomalies`` function to visualize time series data with real and predicted anomalies, highlighting TP, FP, and FN cases.
- Implemented ``PrincipalComponentAnalysis``, ``KernelPrincipalComponentAnalysis`` and
``RobustPrincipalComponentAnalysis`` anomaly detectors.
- Implemented ``HistogramBasedOutlierScore`` anomaly detector.
Expand Down
2 changes: 2 additions & 0 deletions docs/api/visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ Visualization module
.. automodule:: dtaianomaly.visualization

.. autofunction:: dtaianomaly.visualization.plot_time_series_colored_by_score

.. autofunction:: dtaianomaly.visualization.plot_time_series_anomalies
5 changes: 3 additions & 2 deletions dtaianomaly/visualization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
along with the ground truth or predicted anomalies.
"""

from .visualization import plot_time_series_colored_by_score
from .visualization import plot_time_series_colored_by_score, plot_time_series_anomalies

__all__ = [
'plot_time_series_colored_by_score'
'plot_time_series_colored_by_score',
'plot_time_series_anomalies'
]

59 changes: 58 additions & 1 deletion dtaianomaly/visualization/visualization.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import matplotlib.pyplot as plt
import numpy as np


def plot_time_series_colored_by_score(X: np.ndarray, y: np.ndarray, ax: plt.Axes = None, nb_colors: int = 100, **kwargs) -> plt.Figure:
"""
Plots the given time series, and color it according to the given scores.
Expand Down Expand Up @@ -45,3 +44,61 @@ def plot_time_series_colored_by_score(X: np.ndarray, y: np.ndarray, ax: plt.Axes
color = colormap(y_binned[i])
ax.plot([i, i+1], X[[i, i+1]], c=color)
return plt.gcf()

def plot_time_series_anomalies(X: np.ndarray, y_true: np.ndarray, y_pred: np.ndarray, ax: plt.Axes = None, **kwargs) -> plt.Figure:
"""
Visualizes time series data with true and predicted anomalies, highlighting true positives (TP),
false positives (FP), and false negatives (FN).
Parameters
----------
X: np.ndarray of shape (n_samples, n_attributes)
The time series to plot
y_true: np.ndarray of shape (n_samples,)
Ground truth anomaly labels (binary values: 0 or 1).
y_pred: np.ndarray of shape (n_samples,)
Predicted anomaly labels (binary values: 0 or 1).
ax: plt.Axes, default=None
The axes onto which the plot should be made. If None, then a new
figure and axis will be created.
**kwargs:
Arguments to be passed to plt.Figure(), in case ``ax=None``.
Returns
-------
fig: plt.Figure
The figure containing the plotted data.
"""

# Prepare the axis
if ax is None:
plt.figure(**kwargs)
ax = plt.gca()

# Check if all predicted values are binary.
if not np.all(np.isin(y_pred, [0, 1])):
raise ValueError('The predicted anomaly scores must be binary.')

# Identify TP, FP, FN
TP = (y_true == 1) & (y_pred == 1)
FP = (y_true == 0) & (y_pred == 1)
FN = (y_true == 1) & (y_pred == 0)

# Plot the time series
ax.plot(np.arange(len(X)), X, label='Time Series', color='blue', alpha=0.5)

# Scatter points for TP, FP, FN
ax.scatter(np.arange(len(X))[TP], X[TP], color='green', label='TP')
ax.scatter(np.arange(len(X))[FP], X[FP], color='red', label='FP')
ax.scatter(np.arange(len(X))[FN], X[FN], color='orange', label='FN')

# Customize the plot
ax.set_xlabel('Time', fontsize=12)
ax.set_ylabel('Real Values', fontsize=12)
ax.set_title('Time Series Anomaly Detection', fontsize=15)
ax.legend()
ax.grid()

return plt.gcf()


96 changes: 71 additions & 25 deletions notebooks/Anomaly-detection.ipynb

Large diffs are not rendered by default.

Loading

0 comments on commit 662bdec

Please sign in to comment.