mlrun 1.6.4rc8__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mlrun might be problematic. Click here for more details.
- mlrun/__init__.py +11 -1
- mlrun/__main__.py +40 -122
- mlrun/alerts/__init__.py +15 -0
- mlrun/alerts/alert.py +248 -0
- mlrun/api/schemas/__init__.py +5 -4
- mlrun/artifacts/__init__.py +8 -3
- mlrun/artifacts/base.py +47 -257
- mlrun/artifacts/dataset.py +11 -192
- mlrun/artifacts/manager.py +79 -47
- mlrun/artifacts/model.py +31 -159
- mlrun/artifacts/plots.py +23 -380
- mlrun/common/constants.py +74 -1
- mlrun/common/db/sql_session.py +5 -5
- mlrun/common/formatters/__init__.py +21 -0
- mlrun/common/formatters/artifact.py +45 -0
- mlrun/common/formatters/base.py +113 -0
- mlrun/common/formatters/feature_set.py +33 -0
- mlrun/common/formatters/function.py +46 -0
- mlrun/common/formatters/pipeline.py +53 -0
- mlrun/common/formatters/project.py +51 -0
- mlrun/common/formatters/run.py +29 -0
- mlrun/common/helpers.py +12 -3
- mlrun/common/model_monitoring/helpers.py +9 -5
- mlrun/{runtimes → common/runtimes}/constants.py +37 -9
- mlrun/common/schemas/__init__.py +31 -5
- mlrun/common/schemas/alert.py +202 -0
- mlrun/common/schemas/api_gateway.py +196 -0
- mlrun/common/schemas/artifact.py +25 -4
- mlrun/common/schemas/auth.py +16 -5
- mlrun/common/schemas/background_task.py +1 -1
- mlrun/common/schemas/client_spec.py +4 -2
- mlrun/common/schemas/common.py +7 -4
- mlrun/common/schemas/constants.py +3 -0
- mlrun/common/schemas/feature_store.py +74 -44
- mlrun/common/schemas/frontend_spec.py +15 -7
- mlrun/common/schemas/function.py +12 -1
- mlrun/common/schemas/hub.py +11 -18
- mlrun/common/schemas/memory_reports.py +2 -2
- mlrun/common/schemas/model_monitoring/__init__.py +20 -4
- mlrun/common/schemas/model_monitoring/constants.py +123 -42
- mlrun/common/schemas/model_monitoring/grafana.py +13 -9
- mlrun/common/schemas/model_monitoring/model_endpoints.py +101 -54
- mlrun/common/schemas/notification.py +71 -14
- mlrun/common/schemas/object.py +2 -2
- mlrun/{model_monitoring/controller_handler.py → common/schemas/pagination.py} +9 -12
- mlrun/common/schemas/pipeline.py +8 -1
- mlrun/common/schemas/project.py +69 -18
- mlrun/common/schemas/runs.py +7 -1
- mlrun/common/schemas/runtime_resource.py +8 -12
- mlrun/common/schemas/schedule.py +4 -4
- mlrun/common/schemas/tag.py +1 -2
- mlrun/common/schemas/workflow.py +12 -4
- mlrun/common/types.py +14 -1
- mlrun/config.py +154 -69
- mlrun/data_types/data_types.py +6 -1
- mlrun/data_types/spark.py +2 -2
- mlrun/data_types/to_pandas.py +67 -37
- mlrun/datastore/__init__.py +6 -8
- mlrun/datastore/alibaba_oss.py +131 -0
- mlrun/datastore/azure_blob.py +143 -42
- mlrun/datastore/base.py +102 -58
- mlrun/datastore/datastore.py +34 -13
- mlrun/datastore/datastore_profile.py +146 -20
- mlrun/datastore/dbfs_store.py +3 -7
- mlrun/datastore/filestore.py +1 -4
- mlrun/datastore/google_cloud_storage.py +97 -33
- mlrun/datastore/hdfs.py +56 -0
- mlrun/datastore/inmem.py +6 -3
- mlrun/datastore/redis.py +7 -2
- mlrun/datastore/s3.py +34 -12
- mlrun/datastore/snowflake_utils.py +45 -0
- mlrun/datastore/sources.py +303 -111
- mlrun/datastore/spark_utils.py +31 -2
- mlrun/datastore/store_resources.py +9 -7
- mlrun/datastore/storeytargets.py +151 -0
- mlrun/datastore/targets.py +453 -176
- mlrun/datastore/utils.py +72 -58
- mlrun/datastore/v3io.py +6 -1
- mlrun/db/base.py +274 -41
- mlrun/db/factory.py +1 -1
- mlrun/db/httpdb.py +893 -225
- mlrun/db/nopdb.py +291 -33
- mlrun/errors.py +36 -6
- mlrun/execution.py +115 -42
- mlrun/feature_store/__init__.py +0 -2
- mlrun/feature_store/api.py +65 -73
- mlrun/feature_store/common.py +7 -12
- mlrun/feature_store/feature_set.py +76 -55
- mlrun/feature_store/feature_vector.py +39 -31
- mlrun/feature_store/ingestion.py +7 -6
- mlrun/feature_store/retrieval/base.py +16 -11
- mlrun/feature_store/retrieval/dask_merger.py +2 -0
- mlrun/feature_store/retrieval/job.py +13 -4
- mlrun/feature_store/retrieval/local_merger.py +2 -0
- mlrun/feature_store/retrieval/spark_merger.py +24 -32
- mlrun/feature_store/steps.py +45 -34
- mlrun/features.py +11 -21
- mlrun/frameworks/_common/artifacts_library.py +9 -9
- mlrun/frameworks/_common/mlrun_interface.py +5 -5
- mlrun/frameworks/_common/model_handler.py +48 -48
- mlrun/frameworks/_common/plan.py +5 -6
- mlrun/frameworks/_common/producer.py +3 -4
- mlrun/frameworks/_common/utils.py +5 -5
- mlrun/frameworks/_dl_common/loggers/logger.py +6 -7
- mlrun/frameworks/_dl_common/loggers/mlrun_logger.py +9 -9
- mlrun/frameworks/_dl_common/loggers/tensorboard_logger.py +23 -47
- mlrun/frameworks/_ml_common/artifacts_library.py +1 -2
- mlrun/frameworks/_ml_common/loggers/logger.py +3 -4
- mlrun/frameworks/_ml_common/loggers/mlrun_logger.py +4 -5
- mlrun/frameworks/_ml_common/model_handler.py +24 -24
- mlrun/frameworks/_ml_common/pkl_model_server.py +2 -2
- mlrun/frameworks/_ml_common/plan.py +2 -2
- mlrun/frameworks/_ml_common/plans/calibration_curve_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/confusion_matrix_plan.py +2 -3
- mlrun/frameworks/_ml_common/plans/dataset_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/feature_importance_plan.py +3 -3
- mlrun/frameworks/_ml_common/plans/roc_curve_plan.py +4 -4
- mlrun/frameworks/_ml_common/utils.py +4 -4
- mlrun/frameworks/auto_mlrun/auto_mlrun.py +9 -9
- mlrun/frameworks/huggingface/model_server.py +4 -4
- mlrun/frameworks/lgbm/__init__.py +33 -33
- mlrun/frameworks/lgbm/callbacks/callback.py +2 -4
- mlrun/frameworks/lgbm/callbacks/logging_callback.py +4 -5
- mlrun/frameworks/lgbm/callbacks/mlrun_logging_callback.py +4 -5
- mlrun/frameworks/lgbm/mlrun_interfaces/booster_mlrun_interface.py +1 -3
- mlrun/frameworks/lgbm/mlrun_interfaces/mlrun_interface.py +6 -6
- mlrun/frameworks/lgbm/model_handler.py +10 -10
- mlrun/frameworks/lgbm/model_server.py +6 -6
- mlrun/frameworks/lgbm/utils.py +5 -5
- mlrun/frameworks/onnx/dataset.py +8 -8
- mlrun/frameworks/onnx/mlrun_interface.py +3 -3
- mlrun/frameworks/onnx/model_handler.py +6 -6
- mlrun/frameworks/onnx/model_server.py +7 -7
- mlrun/frameworks/parallel_coordinates.py +6 -6
- mlrun/frameworks/pytorch/__init__.py +18 -18
- mlrun/frameworks/pytorch/callbacks/callback.py +4 -5
- mlrun/frameworks/pytorch/callbacks/logging_callback.py +17 -17
- mlrun/frameworks/pytorch/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/pytorch/callbacks/tensorboard_logging_callback.py +23 -29
- mlrun/frameworks/pytorch/callbacks_handler.py +38 -38
- mlrun/frameworks/pytorch/mlrun_interface.py +20 -20
- mlrun/frameworks/pytorch/model_handler.py +17 -17
- mlrun/frameworks/pytorch/model_server.py +7 -7
- mlrun/frameworks/sklearn/__init__.py +13 -13
- mlrun/frameworks/sklearn/estimator.py +4 -4
- mlrun/frameworks/sklearn/metrics_library.py +14 -14
- mlrun/frameworks/sklearn/mlrun_interface.py +16 -9
- mlrun/frameworks/sklearn/model_handler.py +2 -2
- mlrun/frameworks/tf_keras/__init__.py +10 -7
- mlrun/frameworks/tf_keras/callbacks/logging_callback.py +15 -15
- mlrun/frameworks/tf_keras/callbacks/mlrun_logging_callback.py +11 -11
- mlrun/frameworks/tf_keras/callbacks/tensorboard_logging_callback.py +19 -23
- mlrun/frameworks/tf_keras/mlrun_interface.py +9 -11
- mlrun/frameworks/tf_keras/model_handler.py +14 -14
- mlrun/frameworks/tf_keras/model_server.py +6 -6
- mlrun/frameworks/xgboost/__init__.py +13 -13
- mlrun/frameworks/xgboost/model_handler.py +6 -6
- mlrun/k8s_utils.py +61 -17
- mlrun/launcher/__init__.py +1 -1
- mlrun/launcher/base.py +16 -15
- mlrun/launcher/client.py +13 -11
- mlrun/launcher/factory.py +1 -1
- mlrun/launcher/local.py +23 -13
- mlrun/launcher/remote.py +17 -10
- mlrun/lists.py +7 -6
- mlrun/model.py +478 -103
- mlrun/model_monitoring/__init__.py +1 -1
- mlrun/model_monitoring/api.py +163 -371
- mlrun/{runtimes/mpijob/v1alpha1.py → model_monitoring/applications/__init__.py} +9 -15
- mlrun/model_monitoring/applications/_application_steps.py +188 -0
- mlrun/model_monitoring/applications/base.py +108 -0
- mlrun/model_monitoring/applications/context.py +341 -0
- mlrun/model_monitoring/{evidently_application.py → applications/evidently_base.py} +27 -22
- mlrun/model_monitoring/applications/histogram_data_drift.py +354 -0
- mlrun/model_monitoring/applications/results.py +99 -0
- mlrun/model_monitoring/controller.py +131 -278
- mlrun/model_monitoring/db/__init__.py +18 -0
- mlrun/model_monitoring/db/stores/__init__.py +136 -0
- mlrun/model_monitoring/db/stores/base/__init__.py +15 -0
- mlrun/model_monitoring/db/stores/base/store.py +213 -0
- mlrun/model_monitoring/db/stores/sqldb/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/sqldb/models/__init__.py +71 -0
- mlrun/model_monitoring/db/stores/sqldb/models/base.py +190 -0
- mlrun/model_monitoring/db/stores/sqldb/models/mysql.py +103 -0
- mlrun/model_monitoring/{stores/models/mysql.py → db/stores/sqldb/models/sqlite.py} +19 -13
- mlrun/model_monitoring/db/stores/sqldb/sql_store.py +659 -0
- mlrun/model_monitoring/db/stores/v3io_kv/__init__.py +13 -0
- mlrun/model_monitoring/db/stores/v3io_kv/kv_store.py +726 -0
- mlrun/model_monitoring/db/tsdb/__init__.py +105 -0
- mlrun/model_monitoring/db/tsdb/base.py +448 -0
- mlrun/model_monitoring/db/tsdb/helpers.py +30 -0
- mlrun/model_monitoring/db/tsdb/tdengine/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/tdengine/schemas.py +279 -0
- mlrun/model_monitoring/db/tsdb/tdengine/stream_graph_steps.py +42 -0
- mlrun/model_monitoring/db/tsdb/tdengine/tdengine_connector.py +507 -0
- mlrun/model_monitoring/db/tsdb/v3io/__init__.py +15 -0
- mlrun/model_monitoring/db/tsdb/v3io/stream_graph_steps.py +158 -0
- mlrun/model_monitoring/db/tsdb/v3io/v3io_connector.py +849 -0
- mlrun/model_monitoring/features_drift_table.py +134 -106
- mlrun/model_monitoring/helpers.py +199 -55
- mlrun/model_monitoring/metrics/__init__.py +13 -0
- mlrun/model_monitoring/metrics/histogram_distance.py +127 -0
- mlrun/model_monitoring/model_endpoint.py +3 -2
- mlrun/model_monitoring/stream_processing.py +134 -398
- mlrun/model_monitoring/tracking_policy.py +9 -2
- mlrun/model_monitoring/writer.py +161 -125
- mlrun/package/__init__.py +6 -6
- mlrun/package/context_handler.py +5 -5
- mlrun/package/packager.py +7 -7
- mlrun/package/packagers/default_packager.py +8 -8
- mlrun/package/packagers/numpy_packagers.py +15 -15
- mlrun/package/packagers/pandas_packagers.py +5 -5
- mlrun/package/packagers/python_standard_library_packagers.py +10 -10
- mlrun/package/packagers_manager.py +19 -23
- mlrun/package/utils/_formatter.py +6 -6
- mlrun/package/utils/_pickler.py +2 -2
- mlrun/package/utils/_supported_format.py +4 -4
- mlrun/package/utils/log_hint_utils.py +2 -2
- mlrun/package/utils/type_hint_utils.py +4 -9
- mlrun/platforms/__init__.py +11 -10
- mlrun/platforms/iguazio.py +24 -203
- mlrun/projects/operations.py +52 -25
- mlrun/projects/pipelines.py +191 -197
- mlrun/projects/project.py +1227 -400
- mlrun/render.py +16 -19
- mlrun/run.py +209 -184
- mlrun/runtimes/__init__.py +83 -15
- mlrun/runtimes/base.py +51 -35
- mlrun/runtimes/daskjob.py +17 -10
- mlrun/runtimes/databricks_job/databricks_cancel_task.py +1 -1
- mlrun/runtimes/databricks_job/databricks_runtime.py +8 -7
- mlrun/runtimes/databricks_job/databricks_wrapper.py +1 -1
- mlrun/runtimes/funcdoc.py +1 -29
- mlrun/runtimes/function_reference.py +1 -1
- mlrun/runtimes/kubejob.py +34 -128
- mlrun/runtimes/local.py +40 -11
- mlrun/runtimes/mpijob/__init__.py +0 -20
- mlrun/runtimes/mpijob/abstract.py +9 -10
- mlrun/runtimes/mpijob/v1.py +1 -1
- mlrun/{model_monitoring/stores/models/sqlite.py → runtimes/nuclio/__init__.py} +7 -9
- mlrun/runtimes/nuclio/api_gateway.py +769 -0
- mlrun/runtimes/nuclio/application/__init__.py +15 -0
- mlrun/runtimes/nuclio/application/application.py +758 -0
- mlrun/runtimes/nuclio/application/reverse_proxy.go +95 -0
- mlrun/runtimes/{function.py → nuclio/function.py} +200 -83
- mlrun/runtimes/{nuclio.py → nuclio/nuclio.py} +6 -6
- mlrun/runtimes/{serving.py → nuclio/serving.py} +65 -68
- mlrun/runtimes/pod.py +281 -101
- mlrun/runtimes/remotesparkjob.py +12 -9
- mlrun/runtimes/sparkjob/spark3job.py +67 -51
- mlrun/runtimes/utils.py +41 -75
- mlrun/secrets.py +9 -5
- mlrun/serving/__init__.py +8 -1
- mlrun/serving/remote.py +2 -7
- mlrun/serving/routers.py +85 -69
- mlrun/serving/server.py +69 -44
- mlrun/serving/states.py +209 -36
- mlrun/serving/utils.py +22 -14
- mlrun/serving/v1_serving.py +6 -7
- mlrun/serving/v2_serving.py +133 -54
- mlrun/track/tracker.py +2 -1
- mlrun/track/tracker_manager.py +3 -3
- mlrun/track/trackers/mlflow_tracker.py +6 -2
- mlrun/utils/async_http.py +6 -8
- mlrun/utils/azure_vault.py +1 -1
- mlrun/utils/clones.py +1 -2
- mlrun/utils/condition_evaluator.py +3 -3
- mlrun/utils/db.py +21 -3
- mlrun/utils/helpers.py +405 -225
- mlrun/utils/http.py +3 -6
- mlrun/utils/logger.py +112 -16
- mlrun/utils/notifications/notification/__init__.py +17 -13
- mlrun/utils/notifications/notification/base.py +50 -2
- mlrun/utils/notifications/notification/console.py +2 -0
- mlrun/utils/notifications/notification/git.py +24 -1
- mlrun/utils/notifications/notification/ipython.py +3 -1
- mlrun/utils/notifications/notification/slack.py +96 -21
- mlrun/utils/notifications/notification/webhook.py +59 -2
- mlrun/utils/notifications/notification_pusher.py +149 -30
- mlrun/utils/regex.py +9 -0
- mlrun/utils/retryer.py +208 -0
- mlrun/utils/singleton.py +1 -1
- mlrun/utils/v3io_clients.py +4 -6
- mlrun/utils/version/version.json +2 -2
- mlrun/utils/version/version.py +2 -6
- mlrun-1.7.0.dist-info/METADATA +378 -0
- mlrun-1.7.0.dist-info/RECORD +351 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/WHEEL +1 -1
- mlrun/feature_store/retrieval/conversion.py +0 -273
- mlrun/kfpops.py +0 -868
- mlrun/model_monitoring/application.py +0 -310
- mlrun/model_monitoring/batch.py +0 -1095
- mlrun/model_monitoring/prometheus.py +0 -219
- mlrun/model_monitoring/stores/__init__.py +0 -111
- mlrun/model_monitoring/stores/kv_model_endpoint_store.py +0 -576
- mlrun/model_monitoring/stores/model_endpoint_store.py +0 -147
- mlrun/model_monitoring/stores/models/__init__.py +0 -27
- mlrun/model_monitoring/stores/models/base.py +0 -84
- mlrun/model_monitoring/stores/sql_model_endpoint_store.py +0 -384
- mlrun/platforms/other.py +0 -306
- mlrun-1.6.4rc8.dist-info/METADATA +0 -272
- mlrun-1.6.4rc8.dist-info/RECORD +0 -314
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/LICENSE +0 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/entry_points.txt +0 -0
- {mlrun-1.6.4rc8.dist-info → mlrun-1.7.0.dist-info}/top_level.txt +0 -0
|
@@ -11,24 +11,50 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
|
|
15
|
+
import functools
|
|
16
|
+
import sys
|
|
17
|
+
from typing import Callable, Union
|
|
16
18
|
|
|
17
19
|
import numpy as np
|
|
18
20
|
import plotly.graph_objects as go
|
|
19
21
|
from plotly.subplots import make_subplots
|
|
20
22
|
|
|
21
23
|
import mlrun.common.schemas.model_monitoring
|
|
22
|
-
|
|
24
|
+
from mlrun.artifacts import PlotlyArtifact
|
|
23
25
|
|
|
24
26
|
# A type for representing a drift result, a tuple of the status and the drift mean:
|
|
25
|
-
DriftResultType =
|
|
27
|
+
DriftResultType = tuple[
|
|
28
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp, float
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _PlotlyTableArtifact(PlotlyArtifact):
|
|
33
|
+
"""A custom class for plotly table artifacts"""
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
def _disable_table_dragging(figure_html: str) -> str:
|
|
37
|
+
"""
|
|
38
|
+
Disable the table columns dragging by adding the following
|
|
39
|
+
JavaScript code
|
|
40
|
+
"""
|
|
41
|
+
start, end = figure_html.rsplit(";", 1)
|
|
42
|
+
middle = (
|
|
43
|
+
';for (const element of document.getElementsByClassName("table")) '
|
|
44
|
+
'{element.style.pointerEvents = "none";}'
|
|
45
|
+
)
|
|
46
|
+
figure_html = start + middle + end
|
|
47
|
+
return figure_html
|
|
48
|
+
|
|
49
|
+
def get_body(self) -> str:
|
|
50
|
+
"""Get the adjusted HTML representation of the figure"""
|
|
51
|
+
return self._disable_table_dragging(super().get_body())
|
|
26
52
|
|
|
27
53
|
|
|
28
54
|
class FeaturesDriftTablePlot:
|
|
29
55
|
"""
|
|
30
56
|
Class for producing a features drift table. The plot is a table with columns of all the statistics and metrics
|
|
31
|
-
provided with two additional plot columns of the histograms and drift
|
|
57
|
+
provided with two additional plot columns of the histograms and drift status. The rows content will be drawn
|
|
32
58
|
per feature.
|
|
33
59
|
|
|
34
60
|
For example, if the statistics are 'mean', 'min', 'max' and one metric of 'tvd', for 3 features the table will be:
|
|
@@ -48,7 +74,7 @@ class FeaturesDriftTablePlot:
|
|
|
48
74
|
70 # The width for the values of all the statistics and metrics columns.
|
|
49
75
|
)
|
|
50
76
|
_HISTOGRAMS_COLUMN_WIDTH = 180
|
|
51
|
-
|
|
77
|
+
_STATUS_COLUMN_WIDTH = 20
|
|
52
78
|
|
|
53
79
|
# Table rows heights:
|
|
54
80
|
_HEADER_ROW_HEIGHT = 25
|
|
@@ -57,12 +83,13 @@ class FeaturesDriftTablePlot:
|
|
|
57
83
|
# Histograms configurations:
|
|
58
84
|
_SAMPLE_SET_HISTOGRAM_COLOR = "rgb(0,112,192)" # Blue
|
|
59
85
|
_INPUTS_HISTOGRAM_COLOR = "rgb(208,0,106)" # Magenta
|
|
86
|
+
_HISTOGRAM_OPACITY = 0.75
|
|
60
87
|
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
mlrun.common.schemas.model_monitoring.
|
|
64
|
-
mlrun.common.schemas.model_monitoring.
|
|
65
|
-
mlrun.common.schemas.model_monitoring.
|
|
88
|
+
# Status configurations:
|
|
89
|
+
_STATUS_COLORS = {
|
|
90
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.no_detection: "rgb(0,176,80)", # Green
|
|
91
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.potential_detection: "rgb(255,192,0)", # Orange
|
|
92
|
+
mlrun.common.schemas.model_monitoring.constants.ResultStatusApp.detected: "rgb(208,0,106)", # Magenta
|
|
66
93
|
}
|
|
67
94
|
|
|
68
95
|
# Font configurations:
|
|
@@ -79,9 +106,6 @@ class FeaturesDriftTablePlot:
|
|
|
79
106
|
_BACKGROUND_COLOR = "rgb(255,255,255)" # White
|
|
80
107
|
_SEPARATORS_COLOR = "rgb(240,240,240)" # Light grey
|
|
81
108
|
|
|
82
|
-
# File name:
|
|
83
|
-
_FILE_NAME = "table_plot.html"
|
|
84
|
-
|
|
85
109
|
def __init__(self):
|
|
86
110
|
"""
|
|
87
111
|
Initialize the plot producer for later calling the `produce` method.
|
|
@@ -94,50 +118,29 @@ class FeaturesDriftTablePlot:
|
|
|
94
118
|
|
|
95
119
|
def produce(
|
|
96
120
|
self,
|
|
97
|
-
features: List[str],
|
|
98
121
|
sample_set_statistics: dict,
|
|
99
122
|
inputs_statistics: dict,
|
|
100
|
-
metrics:
|
|
101
|
-
drift_results:
|
|
102
|
-
) ->
|
|
123
|
+
metrics: dict[str, Union[dict, float]],
|
|
124
|
+
drift_results: dict[str, DriftResultType],
|
|
125
|
+
) -> _PlotlyTableArtifact:
|
|
103
126
|
"""
|
|
104
127
|
Produce the html code of the table plot with the given information and the stored configurations in the class.
|
|
105
128
|
|
|
106
|
-
:param features: List of all the features names to include in the table. These names expected to be
|
|
107
|
-
in the statistics and metrics dictionaries.
|
|
108
129
|
:param sample_set_statistics: The sample set calculated statistics dictionary.
|
|
109
130
|
:param inputs_statistics: The inputs calculated statistics dictionary.
|
|
110
131
|
:param metrics: The drift detection metrics calculated on the sample set and inputs.
|
|
111
132
|
:param drift_results: The drift results per feature according to the rules of the monitor.
|
|
112
133
|
|
|
113
|
-
:return: The
|
|
134
|
+
:return: The drift table as a plotly artifact.
|
|
114
135
|
"""
|
|
115
|
-
# Plot the drift table:
|
|
116
|
-
features = [
|
|
117
|
-
feature
|
|
118
|
-
for feature in features
|
|
119
|
-
if feature not in mm_constants.FeatureSetFeatures.list()
|
|
120
|
-
]
|
|
121
136
|
figure = self._plot(
|
|
122
|
-
features=
|
|
137
|
+
features=list(inputs_statistics.keys()),
|
|
123
138
|
sample_set_statistics=sample_set_statistics,
|
|
124
139
|
inputs_statistics=inputs_statistics,
|
|
125
140
|
metrics=metrics,
|
|
126
141
|
drift_results=drift_results,
|
|
127
142
|
)
|
|
128
|
-
|
|
129
|
-
# Get its HTML representation:
|
|
130
|
-
figure_html = figure.to_html()
|
|
131
|
-
|
|
132
|
-
# Turn off the table columns dragging by injecting the following JavaScript code:
|
|
133
|
-
start, end = figure_html.rsplit(";", 1)
|
|
134
|
-
middle = (
|
|
135
|
-
';for (const element of document.getElementsByClassName("table")) '
|
|
136
|
-
'{element.style.pointerEvents = "none";}'
|
|
137
|
-
)
|
|
138
|
-
figure_html = start + middle + end
|
|
139
|
-
|
|
140
|
-
return figure_html
|
|
143
|
+
return _PlotlyTableArtifact(figure=figure, key="drift_table_plot")
|
|
141
144
|
|
|
142
145
|
def _read_columns_names(self, statistics_dictionary: dict, drift_metrics: dict):
|
|
143
146
|
"""
|
|
@@ -171,7 +174,7 @@ class FeaturesDriftTablePlot:
|
|
|
171
174
|
self._metrics_columns
|
|
172
175
|
)
|
|
173
176
|
|
|
174
|
-
def _plot_headers_tables(self) ->
|
|
177
|
+
def _plot_headers_tables(self) -> tuple[go.Table, go.Table]:
|
|
175
178
|
"""
|
|
176
179
|
Plot the headers of the table:
|
|
177
180
|
|
|
@@ -207,7 +210,7 @@ class FeaturesDriftTablePlot:
|
|
|
207
210
|
self._FEATURE_NAME_COLUMN_WIDTH,
|
|
208
211
|
*self._value_columns_widths,
|
|
209
212
|
self._HISTOGRAMS_COLUMN_WIDTH,
|
|
210
|
-
self.
|
|
213
|
+
self._STATUS_COLUMN_WIDTH,
|
|
211
214
|
],
|
|
212
215
|
header_fill_color=self._BACKGROUND_COLOR,
|
|
213
216
|
)
|
|
@@ -231,14 +234,14 @@ class FeaturesDriftTablePlot:
|
|
|
231
234
|
[self._FEATURE_NAME_COLUMN_WIDTH]
|
|
232
235
|
+ [self._VALUE_COLUMN_WIDTH]
|
|
233
236
|
* (2 * len(self._statistics_columns) + len(self._metrics_columns))
|
|
234
|
-
+ [self._HISTOGRAMS_COLUMN_WIDTH, self.
|
|
237
|
+
+ [self._HISTOGRAMS_COLUMN_WIDTH, self._STATUS_COLUMN_WIDTH]
|
|
235
238
|
),
|
|
236
239
|
header_fill_color=self._BACKGROUND_COLOR,
|
|
237
240
|
)
|
|
238
241
|
|
|
239
242
|
return header_table, sub_header_table
|
|
240
243
|
|
|
241
|
-
def _separate_feature_name(self, feature_name: str) ->
|
|
244
|
+
def _separate_feature_name(self, feature_name: str) -> list[str]:
|
|
242
245
|
"""
|
|
243
246
|
Separate the given feature name by the maximum length configured in the class. Used for calculating the amount
|
|
244
247
|
of lines required to represent the longest feature name in the table, so the row heights will fit accordingly.
|
|
@@ -299,15 +302,22 @@ class FeaturesDriftTablePlot:
|
|
|
299
302
|
:return: The feature row - `Table` trace.
|
|
300
303
|
"""
|
|
301
304
|
# Add '\n' to the feature name in order to make it fit into its cell:
|
|
302
|
-
|
|
305
|
+
html_feature_name = "<br>".join(self._separate_feature_name(feature_name))
|
|
303
306
|
|
|
304
307
|
# Initialize the cells values list with the bold feature name as the first value:
|
|
305
|
-
cells_values = [f"<b>{
|
|
308
|
+
cells_values = [f"<b>{html_feature_name}</b>"]
|
|
306
309
|
|
|
307
310
|
# Add the statistics columns:
|
|
308
311
|
for column in self._statistics_columns:
|
|
309
312
|
cells_values.append(sample_statistics[column])
|
|
310
|
-
|
|
313
|
+
try:
|
|
314
|
+
cells_values.append(input_statistics[column])
|
|
315
|
+
except KeyError:
|
|
316
|
+
raise ValueError(
|
|
317
|
+
f"The `input_statistics['{feature_name}']` dictionary "
|
|
318
|
+
f"does not include the expected key '{column}'. "
|
|
319
|
+
"Please check the current data."
|
|
320
|
+
)
|
|
311
321
|
|
|
312
322
|
# Add the metrics columns:
|
|
313
323
|
for column in self._metrics_columns:
|
|
@@ -334,25 +344,25 @@ class FeaturesDriftTablePlot:
|
|
|
334
344
|
|
|
335
345
|
return feature_row_table
|
|
336
346
|
|
|
337
|
-
def
|
|
338
|
-
self,
|
|
339
|
-
|
|
347
|
+
def _plot_histogram_bars(
|
|
348
|
+
self,
|
|
349
|
+
figure_add_trace: Callable,
|
|
350
|
+
sample_hist: tuple[list, list],
|
|
351
|
+
input_hist: tuple[list, list],
|
|
352
|
+
showlegend: bool = False,
|
|
353
|
+
) -> None:
|
|
340
354
|
"""
|
|
341
|
-
Plot the feature's histograms to include in the "histograms" column. Both histograms are
|
|
342
|
-
added in the same figure, so they will be on top of each other and not separated. Both histograms are rescaled
|
|
355
|
+
Plot the feature's histograms to include in the "histograms" column. Both histograms are rescaled
|
|
343
356
|
to be from 0.0 to 1.0, so they will be drawn in the same scale regardless the amount of elements they were
|
|
344
357
|
calculated upon.
|
|
345
358
|
|
|
346
|
-
:param
|
|
347
|
-
:param
|
|
359
|
+
:param figure_add_trace: The figure's method that get the histogram and adds it to the figure.
|
|
360
|
+
:param sample_hist: The sample set histogram data.
|
|
361
|
+
:param input_hist: The input histogram data.
|
|
362
|
+
:param showlegend: Show the legend for each histogram or not.
|
|
348
363
|
|
|
349
|
-
:return:
|
|
350
|
-
[0] - Sample set histogram.
|
|
351
|
-
[1] - Input histogram.
|
|
364
|
+
:return: None
|
|
352
365
|
"""
|
|
353
|
-
# Initialize a list to collect the scatters:
|
|
354
|
-
scatters = []
|
|
355
|
-
|
|
356
366
|
# Plot the histograms:
|
|
357
367
|
for name, color, histogram in zip(
|
|
358
368
|
["sample", "input"],
|
|
@@ -363,25 +373,31 @@ class FeaturesDriftTablePlot:
|
|
|
363
373
|
counts, bins = histogram
|
|
364
374
|
# Rescale the counts to be in percentages (between 0.0 to 1.0):
|
|
365
375
|
counts = np.array(counts) / sum(counts)
|
|
376
|
+
hovertext = [""] * len(counts)
|
|
366
377
|
# Convert to NumPy for vectorization:
|
|
367
378
|
bins = np.array(bins)
|
|
379
|
+
if bins[0] == -sys.float_info.max:
|
|
380
|
+
bins[0] = bins[1] - (bins[2] - bins[1])
|
|
381
|
+
hovertext[0] = f"(-inf, {bins[1]})"
|
|
382
|
+
if bins[-1] == sys.float_info.max:
|
|
383
|
+
bins[-1] = bins[-2] + (bins[-2] - bins[-3])
|
|
384
|
+
hovertext[-1] = f"({bins[-2]}, inf)"
|
|
368
385
|
# Center the bins (leave the first one):
|
|
369
386
|
bins = 0.5 * (bins[:-1] + bins[1:])
|
|
370
387
|
# Plot the histogram as a line with filled background below it:
|
|
371
|
-
|
|
388
|
+
histogram_bar = go.Bar(
|
|
372
389
|
x=bins,
|
|
373
390
|
y=counts,
|
|
374
|
-
fill="tozeroy",
|
|
375
391
|
name=name,
|
|
376
|
-
|
|
377
|
-
|
|
392
|
+
marker_color=color,
|
|
393
|
+
opacity=self._HISTOGRAM_OPACITY,
|
|
378
394
|
legendgroup=name,
|
|
395
|
+
hovertext=hovertext,
|
|
396
|
+
showlegend=showlegend,
|
|
379
397
|
)
|
|
380
|
-
|
|
398
|
+
figure_add_trace(histogram_bar)
|
|
381
399
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
def _calculate_row_height(self, features: List[str]) -> int:
|
|
400
|
+
def _calculate_row_height(self, features: list[str]) -> int:
|
|
385
401
|
"""
|
|
386
402
|
Calculate the feature row height according to the given features. The longest feature will set the height to all
|
|
387
403
|
the rows. The height depends on the separations amount of the longest feature name - more '\n' means more pixels
|
|
@@ -401,7 +417,7 @@ class FeaturesDriftTablePlot:
|
|
|
401
417
|
self._FEATURE_ROW_HEIGHT, 1.5 * self._FONT_SIZE * feature_name_seperations
|
|
402
418
|
)
|
|
403
419
|
|
|
404
|
-
def
|
|
420
|
+
def _plot_status_circle(
|
|
405
421
|
self,
|
|
406
422
|
figure: go.Figure,
|
|
407
423
|
row: int,
|
|
@@ -409,8 +425,8 @@ class FeaturesDriftTablePlot:
|
|
|
409
425
|
drift_result: DriftResultType,
|
|
410
426
|
):
|
|
411
427
|
"""
|
|
412
|
-
Plot the drift
|
|
413
|
-
according to the drift status given.
|
|
428
|
+
Plot the drift status - a little circle with color as configured in the
|
|
429
|
+
class. The color will be chosen according to the drift status given.
|
|
414
430
|
|
|
415
431
|
:param figure: The figure (feature row cell) to draw the circle in.
|
|
416
432
|
:param row: The row number.
|
|
@@ -422,12 +438,12 @@ class FeaturesDriftTablePlot:
|
|
|
422
438
|
# row 3) times the plot columns (2 columns has axes in each row) + 2 (to get to the column of the notification):
|
|
423
439
|
axis_number = (row - 3) * 2 + 2
|
|
424
440
|
figure["layout"][f"xaxis{axis_number}"].update(
|
|
425
|
-
range=[0, self.
|
|
441
|
+
range=[0, self._STATUS_COLUMN_WIDTH]
|
|
426
442
|
)
|
|
427
443
|
figure["layout"][f"yaxis{axis_number}"].update(range=[0, row_height])
|
|
428
444
|
|
|
429
445
|
# Get the color:
|
|
430
|
-
notification_color = self.
|
|
446
|
+
notification_color = self._STATUS_COLORS[drift_result[0]]
|
|
431
447
|
half_transparent_notification_color = notification_color.replace(
|
|
432
448
|
"rgb", "rgba"
|
|
433
449
|
).replace(")", ",0.5)")
|
|
@@ -436,8 +452,8 @@ class FeaturesDriftTablePlot:
|
|
|
436
452
|
# size of the text as well):
|
|
437
453
|
y0 = 36 + (row_height - self._FEATURE_ROW_HEIGHT)
|
|
438
454
|
y1 = y0 + self._FONT_SIZE
|
|
439
|
-
x0 = (self.
|
|
440
|
-
x1 = (self.
|
|
455
|
+
x0 = (self._STATUS_COLUMN_WIDTH / 2) - ((y1 - y0) / 2)
|
|
456
|
+
x1 = (self._STATUS_COLUMN_WIDTH / 2) + ((y1 - y0) / 2)
|
|
441
457
|
|
|
442
458
|
# Draw the circle on top of the figure:
|
|
443
459
|
figure.add_shape(
|
|
@@ -456,11 +472,11 @@ class FeaturesDriftTablePlot:
|
|
|
456
472
|
|
|
457
473
|
def _plot(
|
|
458
474
|
self,
|
|
459
|
-
features:
|
|
475
|
+
features: list[str],
|
|
460
476
|
sample_set_statistics: dict,
|
|
461
477
|
inputs_statistics: dict,
|
|
462
|
-
metrics:
|
|
463
|
-
drift_results:
|
|
478
|
+
metrics: dict[str, Union[dict, float]],
|
|
479
|
+
drift_results: dict[str, DriftResultType],
|
|
464
480
|
) -> go.Figure:
|
|
465
481
|
"""
|
|
466
482
|
Plot the drift table using the given data and stored configurations of the class.
|
|
@@ -488,7 +504,7 @@ class FeaturesDriftTablePlot:
|
|
|
488
504
|
self._FEATURE_NAME_COLUMN_WIDTH
|
|
489
505
|
+ sum(self._value_columns_widths)
|
|
490
506
|
+ self._HISTOGRAMS_COLUMN_WIDTH
|
|
491
|
-
+ self.
|
|
507
|
+
+ self._STATUS_COLUMN_WIDTH
|
|
492
508
|
)
|
|
493
509
|
height = 2 * self._HEADER_ROW_HEIGHT + len(features) * row_height
|
|
494
510
|
|
|
@@ -509,7 +525,7 @@ class FeaturesDriftTablePlot:
|
|
|
509
525
|
(self._FEATURE_NAME_COLUMN_WIDTH + sum(self._value_columns_widths))
|
|
510
526
|
/ width,
|
|
511
527
|
self._HISTOGRAMS_COLUMN_WIDTH / width,
|
|
512
|
-
self.
|
|
528
|
+
self._STATUS_COLUMN_WIDTH / width,
|
|
513
529
|
],
|
|
514
530
|
horizontal_spacing=0,
|
|
515
531
|
vertical_spacing=0,
|
|
@@ -520,39 +536,49 @@ class FeaturesDriftTablePlot:
|
|
|
520
536
|
main_figure.add_trace(header_trace, row=1, col=1)
|
|
521
537
|
main_figure.add_trace(sub_header_trace, row=2, col=1)
|
|
522
538
|
|
|
523
|
-
# Start going over the features and plot each row, histogram and
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
#
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
539
|
+
# Start going over the features and plot each row, histogram and status
|
|
540
|
+
for row, feature in enumerate(
|
|
541
|
+
features,
|
|
542
|
+
start=3, # starting from row 3 after the headers
|
|
543
|
+
):
|
|
544
|
+
try:
|
|
545
|
+
# Add the feature values:
|
|
546
|
+
main_figure.add_trace(
|
|
547
|
+
self._plot_feature_row_table(
|
|
548
|
+
feature_name=feature,
|
|
549
|
+
sample_statistics=sample_set_statistics[feature],
|
|
550
|
+
input_statistics=inputs_statistics[feature],
|
|
551
|
+
metrics=metrics[feature],
|
|
552
|
+
row_height=row_height,
|
|
553
|
+
),
|
|
554
|
+
row=row,
|
|
555
|
+
col=1,
|
|
556
|
+
)
|
|
557
|
+
except KeyError:
|
|
558
|
+
raise ValueError(
|
|
559
|
+
"`sample_set_statistics` does not contain the expected "
|
|
560
|
+
f"key '{feature}' from `inputs_statistics`. Please verify "
|
|
561
|
+
"the data integrity.\n"
|
|
562
|
+
f"{sample_set_statistics.keys() = }\n"
|
|
563
|
+
f"{inputs_statistics.keys() = }\n"
|
|
564
|
+
)
|
|
538
565
|
# Add the histograms (both traces are added to the same subplot figure):
|
|
539
|
-
|
|
566
|
+
self._plot_histogram_bars(
|
|
567
|
+
figure_add_trace=functools.partial(
|
|
568
|
+
main_figure.add_trace, row=row, col=2
|
|
569
|
+
),
|
|
540
570
|
sample_hist=sample_set_statistics[feature]["hist"],
|
|
541
571
|
input_hist=inputs_statistics[feature]["hist"],
|
|
572
|
+
# Only the first row should have its legend visible
|
|
573
|
+
showlegend=(row == 3),
|
|
542
574
|
)
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
input_hist.showlegend = False
|
|
546
|
-
main_figure.add_trace(sample_hist, row=row, col=2)
|
|
547
|
-
main_figure.add_trace(input_hist, row=row, col=2)
|
|
548
|
-
# Add the notification (a circle with color according to the drift alert):
|
|
549
|
-
self._plot_notification_circle(
|
|
575
|
+
# Add the status (a circle with color according to the drift status)
|
|
576
|
+
self._plot_status_circle(
|
|
550
577
|
figure=main_figure,
|
|
551
578
|
row=row,
|
|
552
579
|
row_height=row_height,
|
|
553
580
|
drift_result=drift_results[feature],
|
|
554
581
|
)
|
|
555
|
-
row += 1
|
|
556
582
|
|
|
557
583
|
# Configure the layout and axes for height and widths:
|
|
558
584
|
main_figure.update_layout(
|
|
@@ -569,9 +595,11 @@ class FeaturesDriftTablePlot:
|
|
|
569
595
|
"yanchor": "top",
|
|
570
596
|
"y": 1.0 - (self._HEADER_ROW_HEIGHT / height) + 0.002,
|
|
571
597
|
"xanchor": "right",
|
|
572
|
-
"x": 1.0 - (self.
|
|
598
|
+
"x": 1.0 - (self._STATUS_COLUMN_WIDTH / width) - 0.01,
|
|
573
599
|
"bgcolor": "rgba(0,0,0,0)",
|
|
574
600
|
},
|
|
601
|
+
barmode="overlay",
|
|
602
|
+
bargap=0,
|
|
575
603
|
)
|
|
576
604
|
main_figure.update_xaxes(
|
|
577
605
|
showticklabels=False,
|