diff --git a/notebooks/docs/0.8-anomaly-time-series-plot.ipynb b/notebooks/docs/0.8-anomaly-time-series-plot.ipynb new file mode 100644 index 0000000..9a63337 --- /dev/null +++ b/notebooks/docs/0.8-anomaly-time-series-plot.ipynb @@ -0,0 +1,175 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [], + "metadata": { + "collapsed": false + }, + "id": "ab811dec64537290" + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2023-11-20T15:18:16.747426800Z", + "start_time": "2023-11-20T15:18:08.458946500Z" + } + }, + "outputs": [], + "source": [ + "# Import to be able to import python package from src\n", + "import sys\n", + "\n", + "sys.path.insert(0, '../../src')\n", + "import pandas as pd\n", + "import ontime as on\n", + "from ontime.core.time_series import TimeSeries, BinaryTimeSeries\n", + "from ontime.core.plot.anomaly_plot import AnomalyPlot" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [], + "source": [ + "data_ts = on.generators.random_walk().generate(start=pd.Timestamp('2021-01-01'), end=pd.Timestamp('2022-12-31'))\n", + "data_df = data_ts.pd_dataframe()\n", + "data_df.rename(columns={'random_walk': 'data'}, inplace=True)\n", + "data_ts = TimeSeries.from_dataframe(data_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-20T15:18:16.787592800Z", + "start_time": "2023-11-20T15:18:16.754993Z" + } + }, + "id": "eec107566af4e692" + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [], + "source": [ + "# Assuming 'anomalies' is a new column in data_df indicating anomalies with values 0 or 1\n", + "import numpy as np\n", + "\n", + "np.random.seed(42) # Setting seed for reproducibility\n", + "anomalies_df = pd.DataFrame({'anomalies': np.random.choice([0, 1], size=len(data_df), p=[0.99, 0.01])},\n", + " index=data_df.index)\n", + "\n", + "anomalies_ts = BinaryTimeSeries.from_dataframe(anomalies_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-20T15:18:16.821955700Z", + "start_time": "2023-11-20T15:18:16.784900600Z" + } + }, + "id": "d637aa322628a1b2" + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [], + "source": [ + "subset_data_df = anomalies_df.iloc[140:160]\n", + "subset_data_df.loc[:, 'anomalies'] = 1\n", + "subset_data_ts = BinaryTimeSeries.from_dataframe(subset_data_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-20T15:18:16.837741100Z", + "start_time": "2023-11-20T15:18:16.821955700Z" + } + }, + "id": "43742a19bc26e3d8" + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": [ + "collective_anomalies_df = anomalies_df.copy() # Create a copy of anomalies_df\n", + "\n", + "# Initialize the 'anomalies' column in the copy to 0\n", + "collective_anomalies_df['anomalies'] = 0\n", + "\n", + "# Set the values to 1 where the specified conditions on the index are met\n", + "collective_anomalies_df.loc[(\n", + " ((collective_anomalies_df.index >= '2021-05-21') & (collective_anomalies_df.index <= '2021-05-31')) |\n", + " ((collective_anomalies_df.index >= '2021-06-21') & (collective_anomalies_df.index <= '2021-06-30')) |\n", + " ((collective_anomalies_df.index >= '2021-07-21') & (collective_anomalies_df.index <= '2021-07-31'))\n", + "), 'anomalies'] = 1\n", + "\n", + "collective_an_ts = BinaryTimeSeries.from_dataframe(collective_anomalies_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-20T15:18:16.865856700Z", + "start_time": "2023-11-20T15:18:16.837741100Z" + } + }, + "id": "a80e292f0e234acd" + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "data": { + "text/html": "\n\n
\n", + "text/plain": "alt.LayerChart(...)" + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chart = AnomalyPlot.plot_anomalies(data_ts,\n", + " point_anomalies=anomalies_ts,\n", + " contextual_anomalies=subset_data_ts,\n", + " collective_anomalies=collective_an_ts\n", + " )\n", + "chart" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-20T15:18:17.151055500Z", + "start_time": "2023-11-20T15:18:16.865856700Z" + } + }, + "id": "dffe76c6afad027b" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/docs/0_core/0.5-plots.ipynb b/notebooks/docs/0_core/0.5-plots.ipynb index bf633b4..0d0ba6e 100644 --- a/notebooks/docs/0_core/0.5-plots.ipynb +++ b/notebooks/docs/0_core/0.5-plots.ipynb @@ -10,9 +10,14 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 41, "id": "9286e0b8-3c78-4b0f-943c-d219e9840dfe", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.399978600Z", + "start_time": "2023-11-22T14:30:12.220250Z" + } + }, "outputs": [], "source": [ "# Import to be able to import python package from src\n", @@ -22,24 +27,17 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 42, "id": "2028eed7-b1c3-4c9e-b6a0-00433caa7d0f", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "The `LightGBM` module could not be imported. To enable LightGBM support in Darts, follow the detailed instructions in the installation guide: https://github.com/unit8co/darts/blob/master/INSTALL.md\n", - "The `Prophet` module could not be imported. To enable Prophet support in Darts, follow the detailed instructions in the installation guide: https://github.com/unit8co/darts/blob/master/INSTALL.md\n", - "/Users/fred.montet/Library/Caches/pypoetry/virtualenvs/ontime-FpQu8-YN-py3.10/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from tqdm.autonotebook import tqdm\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.438915100Z", + "start_time": "2023-11-22T14:30:12.223262200Z" } - ], + }, + "outputs": [], "source": [ "import pandas as pd\n", - "import numpy as np\n", "import ontime as on\n", "from darts.datasets import EnergyDataset" ] @@ -55,19 +53,14 @@ }, { "cell_type": "code", - "execution_count": 3, - "id": "e9a96d79-0423-4d79-b01d-726193216238", - "metadata": {}, - "outputs": [], - "source": [ - "ts = on.generators.random_walk().generate(start=pd.Timestamp('2022-01-01'), end=pd.Timestamp('2022-12-31'))" - ] - }, - { - "cell_type": "code", - "execution_count": 4, + "execution_count": 43, "id": "db08372d-8ab2-4290-9196-76eb0c275629", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.886891300Z", + "start_time": "2023-11-22T14:30:12.235870500Z" + } + }, "outputs": [], "source": [ "ts = EnergyDataset().load()" @@ -83,9 +76,14 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 44, "id": "009bcbe3-b73c-4355-b280-1bcb3d98e113", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.888403100Z", + "start_time": "2023-11-22T14:30:12.382164600Z" + } + }, "outputs": [], "source": [ "df = ts.pd_dataframe()\n", @@ -96,9 +94,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 45, "id": "7baaa1c5-c460-44bb-a375-f2eff4509cee", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.888403100Z", + "start_time": "2023-11-22T14:30:12.406885100Z" + } + }, "outputs": [], "source": [ "ts = on.TimeSeries.from_dataframe(df)" @@ -114,9 +117,14 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 46, "id": "07b54c1f-4215-43c0-8c81-bb337b9f50fb", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.888403100Z", + "start_time": "2023-11-22T14:30:12.414642100Z" + } + }, "outputs": [], "source": [ "ts_uni = ts['generation solar'].slice(pd.Timestamp('2015'), pd.Timestamp('2016'))\n", @@ -142,17 +150,20 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 47, "id": "93be4c86-a28f-4af1-8fef-a45467195737", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.889413300Z", + "start_time": "2023-11-22T14:30:12.428732Z" + } + }, "outputs": [ { "data": { - "text/plain": [ - "DataTransformerRegistry.enable('vegafusion')" - ] + "text/plain": "DataTransformerRegistry.enable('vegafusion')" }, - "execution_count": 8, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -176,17 +187,20 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 48, "id": "b59bccc6-996a-4200-b697-01582aa47b0a", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.915488800Z", + "start_time": "2023-11-22T14:30:12.434493200Z" + } + }, "outputs": [ { "data": { - "text/plain": [ - "" - ] + "text/plain": "" }, - "execution_count": 9, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -197,17 +211,20 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 49, "id": "100a36d6-eca8-440f-a02d-c5e81d65aa9e", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.915488800Z", + "start_time": "2023-11-22T14:30:12.457801400Z" + } + }, "outputs": [ { "data": { - "text/plain": [ - "ThemeRegistry.enable('default')" - ] + "text/plain": "ThemeRegistry.enable('default')" }, - "execution_count": 10, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -226,9 +243,14 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 50, "id": "1658d150-b09b-483b-ab26-21c2cd677277", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.916483900Z", + "start_time": "2023-11-22T14:30:12.463439600Z" + } + }, "outputs": [], "source": [ "def plot(ts):\n", @@ -261,85 +283,21 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 51, "id": "e577a85e-22e4-4b62-9e38-6ccd673f911b", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.922995100Z", + "start_time": "2023-11-22T14:30:12.470130700Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.Chart(...)" }, - "execution_count": 12, + "execution_count": 51, "metadata": {}, "output_type": "execute_result" } @@ -358,85 +316,21 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 52, "id": "2a4a0582-209b-461a-815b-7d4d4698c0f7", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.940457Z", + "start_time": "2023-11-22T14:30:12.570624900Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.Chart(...)" }, - "execution_count": 13, + "execution_count": 52, "metadata": {}, "output_type": "execute_result" } @@ -455,9 +349,14 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 53, "id": "e619b6a4-ffcd-4e58-bfc5-104062869f25", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.941458500Z", + "start_time": "2023-11-22T14:30:12.778200200Z" + } + }, "outputs": [], "source": [ "def heatmap(ts):\n", @@ -502,85 +401,21 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 54, "id": "95e245b4-d594-45f7-ae7a-04db01fc860d", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.943458900Z", + "start_time": "2023-11-22T14:30:12.778200200Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.Chart(...)" }, - "execution_count": 15, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -599,85 +434,21 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 55, "id": "2401e142-96dd-4158-8817-2145e246727c", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.975917800Z", + "start_time": "2023-11-22T14:30:12.822230300Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.Chart(...)" }, - "execution_count": 16, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -704,9 +475,14 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 56, "id": "9bef85bd-7a76-4f1e-a6fe-fbddfa4d22ea", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:12.975917800Z", + "start_time": "2023-11-22T14:30:12.893670800Z" + } + }, "outputs": [], "source": [ "train, test = ts_uni.split_after(pd.Timestamp('2015-09-01'))" @@ -714,9 +490,14 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 57, "id": "c176fd03-e8e6-4f0c-88ae-7e0d818b320c", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:15.588523400Z", + "start_time": "2023-11-22T14:30:12.901350500Z" + } + }, "outputs": [], "source": [ "gp = on.context.common.GenericPredictor()\n", @@ -725,9 +506,14 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 58, "id": "47f3d67c-9d6a-406e-abf9-524fac45a9af", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:15.635501600Z", + "start_time": "2023-11-22T14:30:15.588523400Z" + } + }, "outputs": [], "source": [ "pred = gp.predict(48)" @@ -743,9 +529,14 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 59, "id": "b248ce99-55fc-4fb6-9e8a-ecab6a14bb3b", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:15.645013200Z", + "start_time": "2023-11-22T14:30:15.635501600Z" + } + }, "outputs": [], "source": [ "def plot_prediction(train_ts, pred_ts=None, test_ts=None):\n", @@ -794,85 +585,21 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 60, "id": "addd63ba-6bfb-474f-8c8f-e665a1adcb4c", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:15.757986400Z", + "start_time": "2023-11-22T14:30:15.641013Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.Chart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.Chart(...)" }, - "execution_count": 21, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } @@ -899,9 +626,14 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 61, "id": "8fc967f7-d01d-47e9-a577-d5e6ed365b55", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.501840800Z", + "start_time": "2023-11-22T14:30:15.758995400Z" + } + }, "outputs": [], "source": [ "gd = on.context.common.GenericDetector()\n", @@ -910,9 +642,14 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 62, "id": "b0bdec28-60a3-4dd5-9ee5-c235076961c8", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.545831Z", + "start_time": "2023-11-22T14:30:18.503938200Z" + } + }, "outputs": [], "source": [ "detected_train = gd.detect(train)\n", @@ -922,9 +659,14 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 63, "id": "30d7fed7-7d30-41a0-b963-b70d6b71c0d7", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.547335300Z", + "start_time": "2023-11-22T14:30:18.539321200Z" + } + }, "outputs": [], "source": [ "# params\n", @@ -937,9 +679,14 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 64, "id": "626777b9-da0f-415c-bb3d-af8d21f9e3d0", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.559180400Z", + "start_time": "2023-11-22T14:30:18.542831100Z" + } + }, "outputs": [], "source": [ "df_train = train_ts.pd_dataframe()\n", @@ -950,9 +697,14 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 65, "id": "687a66b8-c4b6-4833-a650-76026d8375ae", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.568699500Z", + "start_time": "2023-11-22T14:30:18.553358900Z" + } + }, "outputs": [], "source": [ "df_test = test_ts.pd_dataframe()\n", @@ -963,9 +715,14 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": 66, "id": "71094231-780d-4ef5-afe0-34e5dcff2e62", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.572166100Z", + "start_time": "2023-11-22T14:30:18.562187100Z" + } + }, "outputs": [], "source": [ "df_detected_train = detected_train_ts.pd_dataframe()\n", @@ -976,9 +733,14 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": 67, "id": "2f61d989-38b4-43c4-9a29-39f5681730dd", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.600918700Z", + "start_time": "2023-11-22T14:30:18.573167900Z" + } + }, "outputs": [], "source": [ "df_detected_test = detected_test_ts.pd_dataframe()\n", @@ -989,9 +751,14 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": 68, "id": "7a684b1d-ed31-4d40-aeed-b7a4895a8418", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.600918700Z", + "start_time": "2023-11-22T14:30:18.583657800Z" + } + }, "outputs": [], "source": [ "df_predetected = predetected_ts.pd_dataframe()\n", @@ -1002,9 +769,14 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": 69, "id": "999ba4cb-be10-4120-a046-ddc1c7603dc0", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.603037200Z", + "start_time": "2023-11-22T14:30:18.596040300Z" + } + }, "outputs": [], "source": [ "df = pd.concat([df_train, df_test, df_detected_train, df_detected_test, df_predetected])" @@ -1012,9 +784,14 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": 70, "id": "d72b097f-cc3f-415d-b42a-f2e6d9660a81", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.608055900Z", + "start_time": "2023-11-22T14:30:18.601919600Z" + } + }, "outputs": [], "source": [ "# Pivot data to wide form\n", @@ -1023,9 +800,14 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": 71, "id": "dfc74bbe-7ccc-4d82-9faa-3d89a43aa0a7", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.629491900Z", + "start_time": "2023-11-22T14:30:18.608055900Z" + } + }, "outputs": [], "source": [ "chart_signal_train = alt.Chart(df_wide).mark_line().encode(\n", @@ -1039,9 +821,14 @@ }, { "cell_type": "code", - "execution_count": 104, + "execution_count": 72, "id": "c442b6a0-31f6-47cd-9601-26d03af3d409", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.664192100Z", + "start_time": "2023-11-22T14:30:18.629491900Z" + } + }, "outputs": [], "source": [ "chart_signal_test = alt.Chart(df_wide).mark_line(color='lightblue').encode(\n", @@ -1052,9 +839,14 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 73, "id": "42803eed-da17-427b-bd09-aefbba047710", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.664192100Z", + "start_time": "2023-11-22T14:30:18.645503200Z" + } + }, "outputs": [], "source": [ "chart_anomaly_train = alt.Chart(df_wide).transform_filter(\n", @@ -1067,9 +859,14 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": 74, "id": "20d6d00f-eff9-428f-8c8b-ac0534aaf7e4", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.677565100Z", + "start_time": "2023-11-22T14:30:18.661192Z" + } + }, "outputs": [], "source": [ "chart_anomaly_test = alt.Chart(df_wide).transform_filter(\n", @@ -1082,9 +879,14 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": 75, "id": "c9a0cba2-962c-4d55-b90c-f6608e982cd5", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.695046Z", + "start_time": "2023-11-22T14:30:18.679028Z" + } + }, "outputs": [], "source": [ "chart_anomaly_predetected = alt.Chart(df_wide).transform_filter(\n", @@ -1097,85 +899,21 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": 76, "id": "963da1cc-0eaa-4f5c-ae56-b8fb13ef1aea", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.756148600Z", + "start_time": "2023-11-22T14:30:18.695046Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.LayerChart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.LayerChart(...)" }, - "execution_count": 108, + "execution_count": 76, "metadata": {}, "output_type": "execute_result" } @@ -1186,9 +924,14 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": 77, "id": "9d3eb408-3481-4719-9c1a-a7e01107ea54", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.765636600Z", + "start_time": "2023-11-22T14:30:18.757652800Z" + } + }, "outputs": [], "source": [ "def plot_anomalies(ts, ts_anomaly):\n", @@ -1226,85 +969,21 @@ }, { "cell_type": "code", - "execution_count": 114, + "execution_count": 78, "id": "3c50cf82-47d6-4ebc-b376-6143715dbecd", - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2023-11-22T14:30:18.879532700Z", + "start_time": "2023-11-22T14:30:18.762637100Z" + } + }, "outputs": [ { "data": { - "text/html": [ - "\n", - "\n", - "
\n", - "" - ], - "text/plain": [ - "alt.LayerChart(...)" - ] + "text/html": "\n\n
\n", + "text/plain": "alt.LayerChart(...)" }, - "execution_count": 114, + "execution_count": 78, "metadata": {}, "output_type": "execute_result" } @@ -1343,44 +1022,6 @@ "In the add function, only one Mark can be added but as many Stat as desired can be added as parameter.|\n", "\n" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b90fab39-26d3-45c0-88b5-edd17b3f80ae", - "metadata": {}, - "outputs": [], - "source": [ - " chart = alt.Chart(df).mark_line().encode(\n", - " x='time:T',\n", - " y=f'{name}:Q'\n", - " ).properties(\n", - " width=500,\n", - " height=300\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "94c8a288-e122-4c2f-9745-027364f773f1", - "metadata": {}, - "outputs": [], - "source": [ - "chart = on.Chart(ts)\n", - " .add(on.Anomalies(ts_ano))\n", - "\n", - "\n", - "plot = so.Plot(" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee2828bd-82b2-4a8b-a446-938877dcce06", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/notebooks/docs/0_core/0.6-anomaly-frequency.ipynb b/notebooks/docs/0_core/0.6-anomaly-frequency.ipynb index d24af75..c24f4b1 100644 --- a/notebooks/docs/0_core/0.6-anomaly-frequency.ipynb +++ b/notebooks/docs/0_core/0.6-anomaly-frequency.ipynb @@ -4,10 +4,7 @@ "cell_type": "markdown", "id": "7c555cfe9131a67", "metadata": { - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "source": [ "# Anomaly Frequency\n", @@ -48,10 +45,7 @@ "end_time": "2023-10-25T12:33:05.716873700Z", "start_time": "2023-10-25T12:33:05.709405600Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [], "source": [ @@ -67,10 +61,7 @@ "end_time": "2023-10-25T12:33:06.068692300Z", "start_time": "2023-10-25T12:33:05.716873700Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [ { @@ -100,10 +91,7 @@ "end_time": "2023-10-25T12:33:06.554772400Z", "start_time": "2023-10-25T12:33:06.074360Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [ { @@ -132,10 +120,7 @@ "end_time": "2023-10-25T12:33:07.017948600Z", "start_time": "2023-10-25T12:33:06.554772400Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [ { @@ -170,14 +155,11 @@ "end_time": "2023-10-25T12:33:07.028332900Z", "start_time": "2023-10-25T12:33:07.017948600Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [], "source": [ - "anomalies_frequencies = on.context.common.AnomaliesFrequencies(ts_detect)" + "anomalies_frequencies = on.context.common.AnomalyFrequency(ts_detect)" ] }, { @@ -189,10 +171,7 @@ "end_time": "2023-10-25T12:34:06.702046600Z", "start_time": "2023-10-25T12:34:06.437698300Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [ { @@ -231,10 +210,7 @@ "end_time": "2023-10-25T12:34:08.559774100Z", "start_time": "2023-10-25T12:34:08.273890800Z" }, - "collapsed": false, - "jupyter": { - "outputs_hidden": false - } + "collapsed": false }, "outputs": [ { diff --git a/notebooks/docs/0_core/0.7-anomaly-time-series-plot.ipynb b/notebooks/docs/0_core/0.7-anomaly-time-series-plot.ipynb new file mode 100644 index 0000000..c368397 --- /dev/null +++ b/notebooks/docs/0_core/0.7-anomaly-time-series-plot.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Example of anomaly plot" + ], + "metadata": { + "collapsed": false + }, + "id": "ab811dec64537290" + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2023-11-23T12:01:05.303204600Z", + "start_time": "2023-11-23T12:01:00.068161300Z" + } + }, + "outputs": [], + "source": [ + "# Import to be able to import python package from src\n", + "import sys\n", + "\n", + "sys.path.insert(0, '../../src')\n", + "import pandas as pd\n", + "import ontime as on\n", + "from ontime.core.plot.anomaly_plot import AnomalyPlot\n", + "from ontime.core.time_series import BinaryTimeSeries, TimeSeries" + ] + }, + { + "cell_type": "markdown", + "source": [ + "---\n", + "## Load data" + ], + "metadata": { + "collapsed": false + }, + "id": "1ab697b35b8f5f65" + }, + { + "cell_type": "code", + "execution_count": 2, + "outputs": [], + "source": [ + "data_ts = on.generators.random_walk().generate(start=pd.Timestamp('2021-01-01'), end=pd.Timestamp('2022-12-31'))\n", + "data_df = data_ts.pd_dataframe()\n", + "data_df.rename(columns={'random_walk': 'data'}, inplace=True)\n", + "data_ts = TimeSeries.from_dataframe(data_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-23T12:01:05.331721100Z", + "start_time": "2023-11-23T12:01:05.310731700Z" + } + }, + "id": "eec107566af4e692" + }, + { + "cell_type": "markdown", + "source": [ + "---\n", + "## Creating mock anomalies" + ], + "metadata": { + "collapsed": false + }, + "id": "647bf1cab9416df8" + }, + { + "cell_type": "code", + "execution_count": 3, + "outputs": [], + "source": [ + "# Assuming 'anomalies' is a new column in data_df indicating anomalies with values 0 or 1\n", + "import numpy as np\n", + "\n", + "np.random.seed(42) # Setting seed for reproducibility\n", + "anomalies_df = pd.DataFrame({'anomalies': np.random.choice([0, 1], size=len(data_df), p=[0.99, 0.01])},\n", + " index=data_df.index)\n", + "\n", + "anomalies_ts = BinaryTimeSeries.from_dataframe(anomalies_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-23T12:01:05.359268500Z", + "start_time": "2023-11-23T12:01:05.322958900Z" + } + }, + "id": "d637aa322628a1b2" + }, + { + "cell_type": "code", + "execution_count": 4, + "outputs": [], + "source": [ + "subset_data_df = anomalies_df.iloc[140:160]\n", + "subset_data_df.loc[:, 'anomalies'] = 1\n", + "subset_data_ts = BinaryTimeSeries.from_dataframe(subset_data_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-23T12:01:05.359268500Z", + "start_time": "2023-11-23T12:01:05.343839600Z" + } + }, + "id": "43742a19bc26e3d8" + }, + { + "cell_type": "code", + "execution_count": 5, + "outputs": [], + "source": [ + "collective_anomalies_df = anomalies_df.copy() # Create a copy of anomalies_df\n", + "\n", + "# Initialize the 'anomalies' column in the copy to 0\n", + "collective_anomalies_df['anomalies'] = 0\n", + "\n", + "# Set the values to 1 where the specified conditions on the index are met\n", + "collective_anomalies_df.loc[(\n", + " ((collective_anomalies_df.index >= '2021-05-21') & (collective_anomalies_df.index <= '2021-05-31')) |\n", + " ((collective_anomalies_df.index >= '2021-06-21') & (collective_anomalies_df.index <= '2021-06-30')) |\n", + " ((collective_anomalies_df.index >= '2021-07-21') & (collective_anomalies_df.index <= '2021-07-31'))\n", + "), 'anomalies'] = 1\n", + "\n", + "collective_an_ts = BinaryTimeSeries.from_dataframe(collective_anomalies_df)" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-23T12:01:05.411098600Z", + "start_time": "2023-11-23T12:01:05.354269Z" + } + }, + "id": "a80e292f0e234acd" + }, + { + "cell_type": "markdown", + "source": [ + "---\n", + "## Plotting" + ], + "metadata": { + "collapsed": false + }, + "id": "c84cf149443600a9" + }, + { + "cell_type": "code", + "execution_count": 6, + "outputs": [ + { + "data": { + "text/html": "\n\n
\n", + "text/plain": "alt.LayerChart(...)" + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chart = AnomalyPlot.plot_anomalies(data_ts,\n", + " point_anomalies=anomalies_ts,\n", + " contextual_anomalies=subset_data_ts,\n", + " collective_anomalies=collective_an_ts\n", + " )\n", + "chart" + ], + "metadata": { + "collapsed": false, + "ExecuteTime": { + "end_time": "2023-11-23T12:01:05.579865800Z", + "start_time": "2023-11-23T12:01:05.366115200Z" + } + }, + "id": "dffe76c6afad027b" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/getting-started.ipynb b/notebooks/getting-started.ipynb index 2f54b7b..6b1fddc 100644 --- a/notebooks/getting-started.ipynb +++ b/notebooks/getting-started.ipynb @@ -19,7 +19,8 @@ "metadata": {}, "outputs": [], "source": [ - "import ontime as on" + "import ontime as on\n", + "import pandas as pd" ] }, { diff --git a/poetry.lock b/poetry.lock index fa5bae6..07c2a8d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -179,6 +179,37 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} dev = ["anywidget", "black (<24)", "hatch", "ipython", "m2r", "mypy", "pandas-stubs", "pyarrow (>=11)", "pytest", "pytest-cov", "ruff", "types-jsonschema", "types-setuptools", "vega-datasets", "vegafusion[embed] (>=1.4.0)", "vl-convert-python (>=0.13.0)"] doc = ["docutils", "geopandas", "jinja2", "myst-parser", "numpydoc", "pillow (>=9,<10)", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinxext-altair"] +[[package]] +name = "altair-data-server" +version = "0.4.1" +description = "A background data server for Altair charts." +optional = false +python-versions = ">=3.6" +files = [ + {file = "altair_data_server-0.4.1-py3-none-any.whl", hash = "sha256:bd1414d69dbfec22c804b34210491d7313e5edc7736504dfb8c405ded0e2015b"}, + {file = "altair_data_server-0.4.1.tar.gz", hash = "sha256:b39205a48ab2678020fc58739cb973845879ed169cb5addddc9dcbf5a69aeb2b"}, +] + +[package.dependencies] +altair = "*" +portpicker = "*" +tornado = "*" + +[[package]] +name = "altair-viewer" +version = "0.4.0" +description = "Viewer for Altair and Vega-Lite visualizations." +optional = false +python-versions = ">=3.6" +files = [ + {file = "altair_viewer-0.4.0-py3-none-any.whl", hash = "sha256:5da49c52ad9fc56b823cc479b8e5332324d1544b3f7ae4939c25a8585eae5245"}, + {file = "altair_viewer-0.4.0.tar.gz", hash = "sha256:f5d33df775cb9094544f15e9b5788224488f506cf546c708980d2d44c2f93534"}, +] + +[package.dependencies] +altair = "*" +altair-data-server = ">=0.4.0" + [[package]] name = "ansi2html" version = "1.8.0" @@ -809,6 +840,7 @@ files = [ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"}, {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, @@ -817,6 +849,7 @@ files = [ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"}, {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, @@ -825,6 +858,7 @@ files = [ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"}, {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, @@ -833,6 +867,7 @@ files = [ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"}, {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, @@ -1106,6 +1141,20 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "execnet" +version = "2.0.2" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.7" +files = [ + {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, + {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "executing" version = "1.2.0" @@ -1446,6 +1495,7 @@ files = [ {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, @@ -1454,6 +1504,7 @@ files = [ {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, @@ -1483,6 +1534,7 @@ files = [ {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, @@ -1491,6 +1543,7 @@ files = [ {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, @@ -1546,6 +1599,17 @@ files = [ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + [[package]] name = "ipykernel" version = "6.25.1" @@ -1617,6 +1681,27 @@ qtconsole = ["qtconsole"] test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +[[package]] +name = "ipywidgets" +version = "8.1.1" +description = "Jupyter interactive widgets" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ipywidgets-8.1.1-py3-none-any.whl", hash = "sha256:2b88d728656aea3bbfd05d32c747cfd0078f9d7e159cf982433b58ad717eed7f"}, + {file = "ipywidgets-8.1.1.tar.gz", hash = "sha256:40211efb556adec6fa450ccc2a77d59ca44a060f4f9f136833df59c9f538e6e8"}, +] + +[package.dependencies] +comm = ">=0.1.3" +ipython = ">=6.1.0" +jupyterlab-widgets = ">=3.0.9,<3.1.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=4.0.9,<4.1.0" + +[package.extras] +test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] + [[package]] name = "isoduration" version = "20.11.0" @@ -1960,6 +2045,17 @@ docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pyd openapi = ["openapi-core (>=0.16.1,<0.17.0)", "ruamel-yaml"] test = ["hatch", "ipykernel", "jupyterlab-server[openapi]", "openapi-spec-validator (>=0.5.1,<0.7.0)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] +[[package]] +name = "jupyterlab-widgets" +version = "3.0.9" +description = "Jupyter interactive widgets for JupyterLab" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyterlab_widgets-3.0.9-py3-none-any.whl", hash = "sha256:3cf5bdf5b897bf3bccf1c11873aa4afd776d7430200f765e0686bd352487b58d"}, + {file = "jupyterlab_widgets-3.0.9.tar.gz", hash = "sha256:6005a4e974c7beee84060fdfba341a3218495046de8ae3ec64888e5fe19fdb4c"}, +] + [[package]] name = "kiwisolver" version = "1.4.4" @@ -2136,6 +2232,16 @@ files = [ {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, @@ -2367,25 +2473,24 @@ files = [ [[package]] name = "nbclient" -version = "0.8.0" +version = "0.6.8" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.7.0" files = [ - {file = "nbclient-0.8.0-py3-none-any.whl", hash = "sha256:25e861299e5303a0477568557c4045eccc7a34c17fc08e7959558707b9ebe548"}, - {file = "nbclient-0.8.0.tar.gz", hash = "sha256:f9b179cd4b2d7bca965f900a2ebf0db4a12ebff2f36a711cb66861e4ae158e55"}, + {file = "nbclient-0.6.8-py3-none-any.whl", hash = "sha256:7cce8b415888539180535953f80ea2385cdbb444944cdeb73ffac1556fdbc228"}, + {file = "nbclient-0.6.8.tar.gz", hash = "sha256:268fde3457cafe1539e32eb1c6d796bbedb90b9e92bacd3e43d83413734bb0e8"}, ] [package.dependencies] -jupyter-client = ">=6.1.12" -jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -nbformat = ">=5.1" -traitlets = ">=5.4" +jupyter-client = ">=6.1.5" +nbformat = ">=5.0" +nest-asyncio = "*" +traitlets = ">=5.2.2" [package.extras] -dev = ["pre-commit"] -docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +sphinx = ["Sphinx (>=1.7)", "autodoc-traits", "mock", "moto", "myst-parser", "sphinx-book-theme"] +test = ["black", "check-manifest", "flake8", "ipykernel", "ipython", "ipywidgets", "mypy", "nbconvert", "pip (>=18.1)", "pre-commit", "pytest (>=4.1)", "pytest-asyncio", "pytest-cov (>=2.6.1)", "setuptools (>=60.0)", "testpath", "twine (>=1.11.0)", "xmltodict"] [[package]] name = "nbconvert" @@ -2445,6 +2550,24 @@ traitlets = ">=5.1" docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] test = ["pep440", "pre-commit", "pytest", "testpath"] +[[package]] +name = "nbmake" +version = "1.4.6" +description = "Pytest plugin for testing notebooks" +optional = false +python-versions = ">=3.7.0,<4.0.0" +files = [ + {file = "nbmake-1.4.6-py3-none-any.whl", hash = "sha256:233603c9186c659cb42524de36b556197c352ede1f9daeaa1b1141dfad226218"}, + {file = "nbmake-1.4.6.tar.gz", hash = "sha256:874c5b9d99922f88bf0c92a3b869e75bff154edba2538efef0a1d7ad2263f5fb"}, +] + +[package.dependencies] +ipykernel = ">=5.4.0" +nbclient = ">=0.6.6,<0.7.0" +nbformat = ">=5.0.8,<6.0.0" +Pygments = ">=2.7.3,<3.0.0" +pytest = ">=6.1.0" + [[package]] name = "nest-asyncio" version = "1.5.7" @@ -2886,6 +3009,7 @@ files = [ {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, @@ -2895,6 +3019,7 @@ files = [ {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, + {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, @@ -2984,6 +3109,21 @@ tsdownsample = "0.1.2" [package.extras] inline-persistent = ["Flask-Cors (>=3.0.10,<4.0.0)", "jupyter-dash (>=0.4.2)", "kaleido (==0.2.1)"] +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + [[package]] name = "pmdarima" version = "2.0.3" @@ -3029,6 +3169,20 @@ setuptools = ">=38.6.0,<50.0.0 || >50.0.0" statsmodels = ">=0.13.2" urllib3 = "*" +[[package]] +name = "portpicker" +version = "1.6.0" +description = "A library to choose unique available network ports." +optional = false +python-versions = ">=3.6" +files = [ + {file = "portpicker-1.6.0-py3-none-any.whl", hash = "sha256:b2787a41404cf7edbe29b07b9e0ed863b09f2665dcc01c1eb0c2261c1e7d0755"}, + {file = "portpicker-1.6.0.tar.gz", hash = "sha256:bd507fd6f96f65ee02781f2e674e9dc6c99bbfa6e3c39992e3916204c9d431fa"}, +] + +[package.dependencies] +psutil = "*" + [[package]] name = "pre-commit" version = "3.3.3" @@ -3243,6 +3397,48 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-xdist" +version = "3.5.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-xdist-3.5.0.tar.gz", hash = "sha256:cbb36f3d67e0c478baa57fa4edc8843887e0f6cfc42d677530a36d7472b32d8a"}, + {file = "pytest_xdist-3.5.0-py3-none-any.whl", hash = "sha256:d075629c7e00b611df89f490a5063944bee7a4362a5ff11c7cc7824a03dfce24"}, +] + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.2.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -3359,6 +3555,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -3366,8 +3563,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -3384,6 +3588,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -3391,6 +3596,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -4091,12 +4297,20 @@ files = [ {file = "statsmodels-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a6a0a1a06ff79be8aa89c8494b33903442859add133f0dda1daf37c3c71682e"}, {file = "statsmodels-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77b3cd3a5268ef966a0a08582c591bd29c09c88b4566c892a7c087935234f285"}, {file = "statsmodels-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c64ebe9cf376cba0c31aed138e15ed179a1d128612dd241cdf299d159e5e882"}, + {file = "statsmodels-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:229b2f676b4a45cb62d132a105c9c06ca8a09ffba060abe34935391eb5d9ba87"}, {file = "statsmodels-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb471f757fc45102a87e5d86e87dc2c8c78b34ad4f203679a46520f1d863b9da"}, {file = "statsmodels-0.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:582f9e41092e342aaa04920d17cc3f97240e3ee198672f194719b5a3d08657d6"}, {file = "statsmodels-0.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7ebe885ccaa64b4bc5ad49ac781c246e7a594b491f08ab4cfd5aa456c363a6f6"}, {file = "statsmodels-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b587ee5d23369a0e881da6e37f78371dce4238cf7638a455db4b633a1a1c62d6"}, {file = "statsmodels-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ef7fa4813c7a73b0d8a0c830250f021c102c71c95e9fe0d6877bcfb56d38b8c"}, + {file = "statsmodels-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afe80544ef46730ea1b11cc655da27038bbaa7159dc5af4bc35bbc32982262f2"}, {file = "statsmodels-0.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:a6ad7b8aadccd4e4dd7f315a07bef1bca41d194eeaf4ec600d20dea02d242fce"}, + {file = "statsmodels-0.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0eea4a0b761aebf0c355b726ac5616b9a8b618bd6e81a96b9f998a61f4fd7484"}, + {file = "statsmodels-0.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4c815ce7a699047727c65a7c179bff4031cff9ae90c78ca730cfd5200eb025dd"}, + {file = "statsmodels-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:575f61337c8e406ae5fa074d34bc6eb77b5a57c544b2d4ee9bc3da6a0a084cf1"}, + {file = "statsmodels-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8be53cdeb82f49c4cb0fda6d7eeeb2d67dbd50179b3e1033510e061863720d93"}, + {file = "statsmodels-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6f7d762df4e04d1dde8127d07e91aff230eae643aa7078543e60e83e7d5b40db"}, + {file = "statsmodels-0.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:fc2c7931008a911e3060c77ea8933f63f7367c0f3af04f82db3a04808ad2cd2c"}, {file = "statsmodels-0.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3757542c95247e4ab025291a740efa5da91dc11a05990c033d40fce31c450dc9"}, {file = "statsmodels-0.14.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:de489e3ed315bdba55c9d1554a2e89faa65d212e365ab81bc323fa52681fc60e"}, {file = "statsmodels-0.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76e290f4718177bffa8823a780f3b882d56dd64ad1c18cfb4bc8b5558f3f5757"}, @@ -4699,6 +4913,17 @@ MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog"] +[[package]] +name = "widgetsnbextension" +version = "4.0.9" +description = "Jupyter interactive widgets for Jupyter Notebook" +optional = false +python-versions = ">=3.7" +files = [ + {file = "widgetsnbextension-4.0.9-py3-none-any.whl", hash = "sha256:91452ca8445beb805792f206e560c1769284267a30ceb1cec9f5bcc887d15175"}, + {file = "widgetsnbextension-4.0.9.tar.gz", hash = "sha256:3c1f5e46dc1166dfd40a42d685e6a51396fd34ff878742a3e47c6f0cc4a2a385"}, +] + [[package]] name = "xarray" version = "2023.8.0" @@ -4840,4 +5065,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.13" -content-hash = "194a09b71b665376731495a226e0aab6ebc6e1925b34110bd4eb516d9592ca74" +content-hash = "9ffbd33fd17fbf144a09e112c94a73c56b66c324d7a138dc93d8430dc7632ea8" diff --git a/pyproject.toml b/pyproject.toml index 3cb45d5..9492f10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,11 +17,15 @@ vegafusion-python-embed = "^1.4.1" vegafusion = {extras = ["embed"], version = "^1.4.1"} protobuf = "^4.24.4" vega-datasets = "^0.9.0" +ipywidgets = "^8.1.1" +altair-viewer = "^0.4.0" [tool.poetry.group.dev.dependencies] jupyterlab = "^4.0.5" pre-commit = "^3.3.3" black = "^23.7.0" +nbmake = "^1.4.6" +pytest-xdist = "^3.5.0" [build-system] requires = ["poetry-core"] diff --git a/src/ontime/core/plot/__init__.py b/src/ontime/core/plot/__init__.py index f6f83de..829e879 100644 --- a/src/ontime/core/plot/__init__.py +++ b/src/ontime/core/plot/__init__.py @@ -1 +1,2 @@ from . import plots +from . import anomaly_plot diff --git a/src/ontime/core/plot/anomaly_plot.py b/src/ontime/core/plot/anomaly_plot.py new file mode 100644 index 0000000..e6e1056 --- /dev/null +++ b/src/ontime/core/plot/anomaly_plot.py @@ -0,0 +1,212 @@ +import pandas as pd + +from ..time_series import TimeSeries, BinaryTimeSeries +import altair as alt + + +class AnomalyPlot: + _DATA_COLUMN_NAME = "data" + + @staticmethod + def plot_anomalies( + data: TimeSeries, + point_anomalies: BinaryTimeSeries | None = None, + contextual_anomalies: BinaryTimeSeries | None = None, + collective_anomalies: BinaryTimeSeries | None = None, + seasonal_anomalies: BinaryTimeSeries | None = None, + cyclical_anomalies: BinaryTimeSeries | None = None, + ): + """ + Plot the anomalies of the given time series. + each kind of anomaly is plotted in a different subplot. + + :param data: TimeSeries data + :param point_anomalies: BinaryTimeSeries of point anomalies. Will be plotted as points on the graph. + :param contextual_anomalies: BinaryTimeSeries of contextual anomalies. Will be plotted as a line on the graph. + :param collective_anomalies: BinaryTimeSeries of collective anomalies. Will be plotted as an area on the graph. + :param seasonal_anomalies: BinaryTimeSeries of seasonal anomalies. Will be plotted as a line on the graph. + :param cyclical_anomalies: BinaryTimeSeries of cyclical anomalies. Will be plotted as a line on the graph. + + :return: Return an altair chart with the current time series and the anomalies drawn. Data are plot in blue and + anomalies in red. + """ + data_df = data.pd_dataframe() + + chart = ( + alt.Chart(data_df.reset_index()) + .mark_line() + .encode( + x="time:T", + y=alt.Y( + f"{AnomalyPlot._DATA_COLUMN_NAME}:Q", + axis=alt.Axis(title="Values"), + ), + ) + .properties( + title="Chart representing the data and the anomalies over the time", + width=600, + height=400, + ) + ) + + if point_anomalies is not None: + anomalies_df = point_anomalies.pd_dataframe() + anomalies_df["anomalies_y"] = ( + anomalies_df["anomalies"] * data_df[AnomalyPlot._DATA_COLUMN_NAME] + ) + + anomalies_chart = ( + alt.Chart(anomalies_df.reset_index()) + .mark_circle(color="red", size=100) + .encode( + x="time:T", + y="anomalies_y:Q", + ) + .transform_filter(alt.datum.anomalies == 1) + ) + + chart += anomalies_chart + + if contextual_anomalies is not None: + chart = AnomalyPlot._make_line_chart(data_df, chart, contextual_anomalies) + + if collective_anomalies is not None: + chart = AnomalyPlot._make_area_chart(data_df, chart, collective_anomalies) + + if seasonal_anomalies is not None: + chart = AnomalyPlot._make_line_chart(data_df, chart, seasonal_anomalies) + + if cyclical_anomalies is not None: + chart = AnomalyPlot._make_line_chart(data_df, chart, cyclical_anomalies) + + return chart + + @staticmethod + def _make_line_chart( + data: pd.DataFrame, actual_chart: alt.Chart, anomalies: BinaryTimeSeries + ) -> alt.Chart: + """ + Make a line chart with the given anomalies. + + :param data: TimeSeries within the data that are plotted in the chart. + :param actual_chart: Chart that will be updated with the anomalies. + :param anomalies: BinaryTimeSeries of anomalies that will be plotted in red on the chart. + + :return: Return an altair chart with the current time series and the anomalies drawn. + """ + array_anomalies_df = AnomalyPlot.split_continuous_series(anomalies) + chart_total = actual_chart + for anomalies_df in array_anomalies_df: + anomalies_df["anomalies_y"] = ( + anomalies_df["anomalies"] * data[AnomalyPlot._DATA_COLUMN_NAME] + ) + chart = ( + alt.Chart(anomalies_df.reset_index()) + .mark_line(color="red", strokeWidth=2.5) + .encode( + x="time:T", + y="anomalies_y:Q", + ) + ) + chart_total += chart + + return chart_total + + @staticmethod + def _make_area_chart( + data_df: pd.DataFrame, actual_chart: alt.Chart, anomalies: BinaryTimeSeries + ) -> alt.Chart: + """ + Adding background to the chart with the given anomalies. + + :param data_df: TimeSeries within the data that are plotted in the chart. + :param actual_chart: Chart that will be updated with the anomalies. + :param anomalies: BinaryTimeSeries of anomalies that will be used to color the background in red on the chart. + + :return: Return an altair chart with the current time series and the anomalies drawn. + """ + + y_max = data_df[AnomalyPlot._DATA_COLUMN_NAME].max() + y_min = data_df[AnomalyPlot._DATA_COLUMN_NAME].min() + + delta = (y_max - y_min) * 0.1 + + array_anomalies_df = AnomalyPlot.split_continuous_series(anomalies) + chart_total = None + for anomalies_df in array_anomalies_df: + anomalies_df["max"] = y_max + delta + anomalies_df["min"] = y_min - delta + + chart = ( + alt.Chart(anomalies_df.reset_index()) + .mark_area(color="red", opacity=0.3) + .encode( + x="time:T", + y="min:Q", + y2="max:Q", + ) + ) + + if chart_total is None: + chart_total = chart + else: + chart_total += chart + + if chart_total is not None: + # Put our chart as background + return chart_total + actual_chart + return actual_chart + + @staticmethod + def split_continuous_series(anomalies: BinaryTimeSeries) -> list[pd.DataFrame]: + """ + Split a continuous series of anomalies into multiple series of anomalies. The response covert all the anomalies + in the BinaryTimeSeries but change its structure to have a list with one df by continuous series of 1. Zeros are + not represented anymore. + + :param anomalies: BinaryTimeSeries of anomalies that will be split. + + :return: Return a list of DataFrame of anomalies. + """ + anomalies_df = anomalies.pd_dataframe() + + # Initialize variables + result_dfs = [] + current_value = 0 + current_df = None + + # Iterate through each row of the base_df + for idx, row in anomalies_df.iterrows(): + value = row["anomalies"] + + # If value changes + if value != current_value: + if current_df is not None: + # Save the current DataFrame into the array + current_df = current_df.rename_axis("time") + result_dfs.append(current_df) + current_df = None + + else: + # Create a new DataFrame with the same structure as base_df + current_df = pd.DataFrame(columns=anomalies_df.columns) + # Save the current row in the new DataFrame + current_df = pd.concat( + [current_df, pd.DataFrame([row], index=[idx])] + ) + + current_value = value + + else: + # If value does not change + if current_df is not None: + # Save the row in the current DataFrame + current_df = pd.concat( + [current_df, pd.DataFrame([row], index=[idx])] + ) + + if current_value == 1: + current_df = current_df.rename_axis("time") + result_dfs.append(current_df) + + return result_dfs diff --git a/src/ontime/core/time_series/binary_time_series.py b/src/ontime/core/time_series/binary_time_series.py index 19df797..443d062 100644 --- a/src/ontime/core/time_series/binary_time_series.py +++ b/src/ontime/core/time_series/binary_time_series.py @@ -1,6 +1,5 @@ import xarray as xr import numpy as np - from .resticted_time_series import RestrictedTimeSeries diff --git a/src/ontime/core/time_series/probabilistic_time_series.py b/src/ontime/core/time_series/probabilistic_time_series.py index 6296837..d31d3b7 100644 --- a/src/ontime/core/time_series/probabilistic_time_series.py +++ b/src/ontime/core/time_series/probabilistic_time_series.py @@ -1,6 +1,5 @@ import xarray as xr import numpy as np - from .resticted_time_series import RestrictedTimeSeries diff --git a/src/ontime/core/time_series/time_series.py b/src/ontime/core/time_series/time_series.py index abce624..dfb4e09 100644 --- a/src/ontime/core/time_series/time_series.py +++ b/src/ontime/core/time_series/time_series.py @@ -1,6 +1,5 @@ from __future__ import annotations from typing import List - from darts import TimeSeries as DartsTimeSeries import pandas as pd import xarray as xr