python/examples/basic/Constraints_Suite.ipynb
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
">### 🚩 *Create a free WhyLabs account to get more value out of whylogs!*<br> \n",
">*Did you know you can store, visualize, and monitor whylogs profiles with the [WhyLabs Observability Platform](https://whylabs.ai/whylogs-free-signup?utm_source=whylogs-Github&utm_medium=whylogs-example&utm_campaign=Constraints_Suite)? Sign up for a [free WhyLabs account](https://whylabs.ai/whylogs-free-signup?utm_source=whylogs-Github&utm_medium=whylogs-example&utm_campaign=Constraints_Suite) to leverage the power of whylogs and WhyLabs together!*"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simple Constraints - Examples and Usage"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/whylabs/whylogs/blob/mainline/python/examples/basic/Constraints_Suite.ipynb)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"> This is a `whylogs v1` example. For the analog feature in `v0`, please refer to [this example](https://github.com/whylabs/whylogs/blob/maintenance/0.7.x/examples/Constraints_Suite.ipynb)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example, we'll show how to define a number of simple constraints and examples on how to use them. For the basics on how to build your own set of constraints, see the example - [Data Validation with Metric Constraints](https://whylogs.readthedocs.io/en/stable/examples/advanced/Metric_Constraints.html).\n",
"\n",
"The constraints are listed according to the metric namespace used when defining them. For each category, we will create helper functions for simple and popular constraints. Each helper function has a brief explanation in its docstring. After defining the helper functions, we'll show a simple example on how to build the constraints out of the functions and visualize them as a report with the visualization module."
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"> Note: The constraints shown here are still experimental and subject to further changes. Stay tuned for upgrades!"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Completeness Constraints\n",
"\n",
"| constraint | parameters | semantic | metric |\n",
"|------------------------------|---------------------|-------------------------------------------------------|--------|\n",
"| no_missing_values | column name | Checks that are no missing values in the column | Counts |\n",
"| null_values_below_number | column name, number | Number of null values must be below given number. | Counts |\n",
"| null_percentage_below_number | column name, number | Percentage of null values must be below given number. | Counts |"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Consistency Constraints\n",
"\n",
"| constraint | parameters | semantic | metric |\n",
"|-----------------------------------|----------------------------|----------------------------------------------------------------------------------------|----------------|\n",
"| greater_than_number | column name | Minimum value of given column must be above defined number. | Distribution |\n",
"| smaller_than_number | column name, number | Maximum value of given column must be below defined number. | Distribution |\n",
"| is_in_range | column name, lower, upper | Checks that all of column's values are in defined range (inclusive). | Distribution |\n",
"| is_non_negative | column name | Checks if a column is non negative. | Distribution |\n",
"| n_most_common_items_in_set | column name, reference set | Checks if the top n most common items appear in the dataset. | Frequent Items |\n",
"| frequent_strings_in_reference_set | column name, reference set | Checks if a set of variables appear in the frequent strings for a string column. | Frequent Items |\n",
"| count_below_number | column name, number | Checks if elements in a column are below given number. | Counts |\n",
"| distinct_number_in_range | column name, lower, upper | Checks if number of distinct categories is between lower and upper values (inclusive). | Cardinality |\n",
"| column_is_nullable_integral | column name | Check if column contains only records of specific datatype. | Types |\n",
"| column_is_nullable_boolean | column name | Check if column contains only records of specific datatype. | Types |\n",
"| column_is_nullable_fractional | column name | Check if column contains only records of specific datatype. | Types |\n",
"| column_is_nullable_object | column name | Check if column contains only records of specific datatype. | Types |\n",
"| column_is_nullable_string | column name | Check if column contains only records of specific datatype. | Types |"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Condition Count Constraints\n",
"\n",
"Please refer to the example [Metric Constraints with Condition Count Metrics](https://github.com/whylabs/whylogs/blob/mainline/python/examples/advanced/Metric_Constraints_with_Condition_Count_Metrics.ipynb) for examples on how to use these constraints.\n",
"\n",
"| constraint | parameters | semantic | metric |\n",
"|------------------------|-------------------------------------|--------------------------------------------------------------------------------------|--------------|\n",
"| condition_meets | column name, condition_name | Fails if condition not met at least once. | Condition Count |\n",
"| condition_never_meets | column name, condition_name | Fails if condition is met at least once | Condition Count |\n",
"| condition_count_below | column name, condition_name, max_count | Fails if condition is met more than max count | Condition Count |\n",
"\n",
"## Statistics Constraints\n",
"\n",
"| constraint | parameters | semantic | metric |\n",
"|------------------------|-------------------------------------|--------------------------------------------------------------------------------------|--------------|\n",
"| mean_between_range | column name, lower, upper | Mean must be between range defined by lower and upper bounds. | Distribution |\n",
"| stddev_between_range | column name, lower, upper | Standard deviarion must be between range defined by lower and upper bounds. | Distribution |\n",
"| quantile_between_range | column name, quantile, lower, upper | Q-th quantile value must be withing the range defined by lower and upper boundaries. | Distribution |"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Table of Contents\n",
"\n",
"- [Installing and Importing Modules](#pre)\n",
"- [Distribution Metrics Constraints](#distribution)\n",
"- [Frequent Items/Frequent Strings Metrics Constraints](#frequent)\n",
"- [Counters Constraints](#counts)\n",
"- [Cardinality Constraints](#card)\n",
"- [Types Constraints](#types)\n",
"- [Combined Metrics Constraints](#comb)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Installing whylogs and importing modules <a class=\"anchor\" id=\"pre\"></a>\n",
"\n",
"If you haven't already, install whylogs:"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"# Note: you may need to restart the kernel to use updated packages.\n",
"%pip install 'whylogs[viz]'"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, let's import the helper functions needed to define the constraints:"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"from whylogs.core.constraints import ConstraintsBuilder\n",
"from whylogs.core.constraints.factories import (\n",
" greater_than_number,\n",
" is_in_range,\n",
" is_non_negative,\n",
" mean_between_range,\n",
" smaller_than_number,\n",
" stddev_between_range,\n",
" quantile_between_range\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples - Distribution Metrics Constraints"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import whylogs as why\n",
"import pandas as pd\n",
"data = {\n",
" \"animal\": [\"cat\", \"hawk\", \"snake\", \"cat\", \"mosquito\"],\n",
" \"legs\": [4, 2, 0, 4, 6],\n",
" \"weight\": [4.3, 1.8, 1.3, 4.1, 5.5e-6],\n",
"}\n",
"\n",
"results = why.log(pd.DataFrame(data))\n",
"profile_view = results.view()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div></div><iframe srcdoc=\"<!DOCTYPE html>\n",
"<html lang="en">\n",
" <head>\n",
" <meta charset="UTF-8" />\n",
" <meta http-equiv="X-UA-Compatible" content="IE=edge" />\n",
" <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n",
" <meta name="description" content="" />\n",
" <meta name="author" content="" />\n",
"\n",
" <title>Profile Visualizer | whylogs</title>\n",
"\n",
" <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />\n",
" <link rel="preconnect" href="https://fonts.googleapis.com" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n",
" <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" />\n",
" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />\n",
"\n",
" <script\n",
" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"\n",
" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="\n",
" crossorigin="anonymous"\n",
" referrerpolicy="no-referrer"\n",
" ></script>\n",
"\n",
" <style type="text/css">\n",
"\n",
" /* Screen on smaller screens */\n",
" .no-responsive {\n",
" display: none;\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1031;\n",
" width: 100vw;\n",
" height: 100vh;\n",
" background-color: var(--tealBackground);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" }\n",
"\n",
" @media screen and (min-width: 1000px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
"\n",
" .no-responsive__content {\n",
" max-width: 600px;\n",
" width: 100%;\n",
" padding: 0 24px;\n",
" }\n",
"\n",
" .no-responsive__title {\n",
" font-size: 96px;\n",
" font-weight: 300;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.167;\n",
" }\n",
"\n",
" .no-responsive__text {\n",
" margin: 0;\n",
" font-size: 16px;\n",
" font-weight: 400;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.5;\n",
" }\n",
"\n",
" .header-title {\n",
" font-size: 26px;\n",
" font-weight: 700;\n",
" color: #444444;\n",
" }\n",
"\n",
" .tooltip-full-number {\n",
" position: relative;\n",
" display: inline-block;\n",
" }\n",
"\n",
" .tooltip-full-number .tooltiptext {\n",
" visibility: hidden;\n",
" background: black;\n",
" color: white;\n",
" border: 1px solid black;\n",
" text-align: start;\n",
" padding: 3px;\n",
" position: absolute;\n",
" z-index: 1;\n",
" top: 0;\n",
" left: 100%;\n",
" margin-left: 5px;\n",
" opacity: 0;\n",
" transition: opacity 0.5s;\n",
" font-size: 13px;\n",
" font-weight: normal;\n",
" line-height: 100%;\n",
" }\n",
"\n",
" .tooltip-full-number:hover .tooltiptext {\n",
" visibility: visible;\n",
" opacity: 1;\n",
" }\n",
"\n",
"\n",
" .wl-compare-profile {\n",
" position: relative;\n",
" left: 0;\n",
" padding: 30px;\n",
" margin-bottom: 20px;\n",
" background: var(--white);;\n",
" border-bottom: 1px solid #CED4DA;\n",
" }\n",
"\n",
" .alert-list {\n",
" padding: 30px;\n",
" padding-top: 0;\n",
" }\n",
"\n",
" .drift-detection {\n",
" justify-content: space-between;\n",
" align-items: center;\n",
" }\n",
"\n",
" .drift-detection-info-circle {\n",
" width: 15px;\n",
" height: 15px;\n",
" border-radius: 50px;\n",
" display: inline-block;\n",
" margin-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item {\n",
" padding-right: 20px;\n",
" }\n",
"\n",
" .drift-detection-info-title {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 22px;\n",
" line-height: 130%;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-count {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 14px;\n",
" line-height: 16px;\n",
" color: #000000;\n",
" padding-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-name {\n",
" font-family: Arial;\n",
" font-style: normal;\n",
" font-weight: normal;\n",
" font-size: 12px;\n",
" line-height: 14px;\n",
" color: #000000;\n",
" }\n",
"\n",
" .drift-detection-search-input {\n",
" display: flex;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 170px;\n",
" padding-left: 10px;\n",
" }\n",
"\n",
" .drift-detection-search-input img{\n",
" margin-right: 5px;\n",
" }\n",
"\n",
" .drift-detection-search-input input::placeholder {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 13px;\n",
" line-height: 16px;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .dropdown-container {\n",
" position: absolute;\n",
" right: 30px;\n",
" top: 80px;\n",
" z-index: 999;\n",
" background: #FFFFFF;\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.05);\n",
" border-radius: 4px;\n",
" padding: 10px !important;\n",
" border: none !important;\n",
" }\n",
"\n",
" .filter-options-title {\n",
" width: 240px;\n",
" }\n",
"\n",
" .filter-options-title p {\n",
" margin: 0;\n",
" }\n",
"\n",
" .form-check-input:checked {\n",
" background-color: #0E7384;\n",
" border-color: #0E7384;\n",
" }\n",
"\n",
" .form-check-input[type=checkbox] {\n",
" border-radius: 2px;\n",
" }\n",
"\n",
" .search-input{\n",
" padding-top: 0 !important;\n",
" padding-bottom: 0 !important;\n",
" }\n",
"\n",
" .search-input input{\n",
" border: none;\n",
" background: none;\n",
" outline: none;\n",
" height: 40px;\n",
" width: 100%;\n",
" font-size: 14px;\n",
" }\n",
"\n",
" .search-input img{\n",
" height: 19px;\n",
" pointer-events: none;\n",
" }\n",
"\n",
" input::placeholder {\n",
" color: var(--secondaryLight1000);\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .close-filter-button {\n",
" display: flex;\n",
" justify-content: center;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #369BAC;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 40px;\n",
" height: 40px;\n",
" cursor: pointer;\n",
" margin-left: 10px;\n",
" }\n",
"\n",
" .statistic-number-title {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 20px;\n",
" color: #6C757D;\n",
" }\n",
"\n",
" .statistic-number {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 20px;\n",
" line-height: 140%;\n",
" display: flex;\n",
" align-items: center;\n",
" color: #4F595B;\n",
" }\n",
"\n",
" .full-summary-statistics-wrap {\n",
" padding: 20px;\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .statistics-list {\n",
" width: 100% ;\n",
" }\n",
"\n",
" mark {\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 140%;\n",
" }\n",
"\n",
" .blue-mark {\n",
" background-color: #369BAC1A;\n",
" color: #369BAC;\n",
" }\n",
"\n",
" .red-mark {\n",
" background-color: #FFEFEE;\n",
" color: #F5473C;\n",
" }\n",
"\n",
" .alert-tag {\n",
" height: 27px;\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 12px;\n",
" line-height: 140%;\n",
" color: #FFFFFF;\n",
" }\n",
"\n",
" .turquoise-background-color {\n",
" background-color: #1DBB42;\n",
" }\n",
"\n",
" .bordeaux-background-color {\n",
" background-color: #C6462A;\n",
" }\n",
"\n",
" .border-solid-gray {\n",
" border: 1px solid #CED4DA;\n",
" border-radius: 4px;\n",
" }\n",
"\n",
" .display-flex {\n",
" display: flex;\n",
" }\n",
"\n",
" .justify-content-space-between {\n",
" justify-content: space-between;\n",
" }\n",
"\n",
" .justify-content-center {\n",
" justify-content: center;\n",
" }\n",
"\n",
" .align-items-center {\n",
" align-items: center;\n",
" }\n",
"\n",
" .align-items-flex-start {\n",
" align-items: flex-start;\n",
" }\n",
"\n",
" .padding-right-30 {\n",
" padding-right: 30px;\n",
" }\n",
"\n",
" .notif-circle-container{\n",
" position: absolute;\n",
" top: 25px;\n",
" right: 25px;\n",
" padding: 5.3px;\n",
" border-radius: 50%;\n",
" background-color: white;\n",
" cursor: pointer;\n",
" }\n",
"\n",
" .notif-circle {\n",
" position: absolute;\n",
" top: 2px;\n",
" right: 2px;\n",
" padding: 3.3px;\n",
" border-radius: 50%;\n",
" background-color: #F2994A;\n",
" }\n",
"\n",
" .alert-list-text {\n",
" width: 70%\n",
" }\n",
"\n",
" @media screen and (min-width: 500px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
" </style>\n",
" </head>\n",
"\n",
" <body id="generated-html"></body>\n",
"\n",
" <script id="entry-template" type="text/x-handlebars-template">\n",
" \n",
" <div class="desktop-content">\n",
" <div class="full-summary-statistics-wrap">\n",
" <div class="full-summary-statistics">\n",
" <div>\n",
" <div class="display-flex justify-content-center">\n",
" <div class="statistics-list border-solid-gray">\n",
" <div>\n",
" <div class="wl-compare-profile" id="compare-profile">\n",
" <div class="drift-detection-wrap">\n",
" <div class="drift-detection display-flex align-items-flex-start">\n",
" <div class="drift-detection-info flex-direction-colum">\n",
" <div class="drift-detection-info-title-wrap display-flex">\n",
" <p class="drift-detection-info-title">\n",
" Constraints Report\n",
" </p>\n",
" </div>\n",
"\n",
" <!-- </div> -->\n",
" </div>\n",
" <div class="drift-detection-search-input-wrap display-flex">\n",
" <div class="drift-detection-search-input search-input">\n",
" <input type="text" id="wl__feature-search" placeholder="Quick search..."/>\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGdSURBVHgBpZK7TkJBEIZnZoVocdTYyQNALxpNKPQBMEaNJsbCRMKhl8ISWwt6AaksCF5iTHgAGhJD4AHkAaAzGiwUsjvOQnO4SYh/cXbPzO43OxcEj9Zy92EiFSXNIfvPyE1kKFfdoxJMENpP6DrvLC0vJoEwCgwto7DWcxoIIHBYbA3NmKwnDltjAeuZhyul1DaTTlfPB6Nt5Z53DOgky4P875+nlctY2+unjZviLklkJhi5bPUa3y/7qJuQUM7PinMy7CdQc1Gh16vnBxPzrMROmlKQEgKNASAHLQCmSIGpS75O+O5pdQAgVXaIqTkNwDDXHmcnW3VmHZoGMLoTsOt88+NrAMCIZdu+iLTyTwKRa1Md6YKfOgXbzO7K8sWku5u5RxcRV5EpPezrzcHGbXEXWaUkgkweZ/UC9YrK3zqggFw5FBZfm8EUavHj7AjAKpIvBDrGn+pNnlcyhYgqbcC41idr1gvB4SdZkDbzQa21gwv0Vj07aPTtL07XdDOyDXohCDNoHIRmAVRie20f+RKybRDQDvxHkXy/7b/DrayncLbMwQAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="wl__dropdown_arrow-icon">\n",
" <div onclick="openFilter()" class="close-filter-button">\n",
" <div class="display-flex close-filter-icon d-none">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADFSURBVHgBfY+xDcIwEEXvnLQBZQkYAEhDwwKpEEK0CCZgAEjJCEmgjYSAygxAHTZgFRSOsyUjY5mcZFnn/+78PwBXf3+MoKWUPuYjVBPFnTwpr9t/oNJfcTfXsAhRAlDqDhhQIPYgpAqNMDqcUqSAYZT1epr9gAHt6uXshvYme4DYHQJNDKh0dD0m5WXB10Y3Fqjtuh7fROn3oREDWxfeMLyRsMnc0OgDzdduaA0Pi3Plgr7Q2kaAePeBqh6rueSNBVt6fgCwBV1JLF3rlAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="display-flex filter-icon">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACSSURBVHgBrZLBCYAwDEWTUjw7igcdwI1cxkNXUJzBEVzFAbSVKoKmaVrEB6GHJv/w+AACtRk7P9IONv1QOYUl96k0zv61m2tjARoLtSDI3EFsgIJ4uoXrMLazO72CRG2mzg/8BSdVlEjhpGZJjAWdAZJECpWalEhJSs1pHuUlMad5FFai1Lwg4Ckx1TxKIPFL8w55mEWd8VjPGAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" </div>\n",
" <span class="notif-circle-container">\n",
" <span class="notif-circle"></span>\n",
" </span>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="dropdown-container flex-direction-colum mb-2 d-none" id="dropdown-container">\n",
" <div class="filter-options">\n",
" <div class="filter-options-title space-between dropdown">\n",
" <p>Select a view:</p>\n",
" </div>\n",
" <div class="form-check mb-1 mt-2">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Discrete"\n",
" id="inferredDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredDiscrete">\n",
" Failed constraints (<span class="wl__feature-count--discrete"></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Non-discrete"\n",
" id="inferredNonDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredNonDiscrete">\n",
" Passed constraints (<span\n",
" class="wl__feature-count--non-discrete"\n",
" ></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Unknown"\n",
" id="inferredUnknown"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredUnknown">\n",
" All constraints (<span class="wl__feature-count--unknown"></span>)\n",
" </label>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="alert-list" id="alert-list">\n",
" {{{alertLIst this}}}\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="no-responsive">\n",
" <div class="no-responsive__content">\n",
" <h1 class="no-responsive__title">Hold on! :)</h1>\n",
" <p class="no-responsive__text">\n",
" It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is\n",
" best experienced on a desktop computer. Please try maximizing this window or switching to another device. We\n",
" are working on adding support for a larger variety of devices.\n",
" </p>\n",
" </div>\n",
" </div>\n",
" \n",
" </script>\n",
"\n",
" <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>\n",
"\n",
" <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n",
"\n",
" <script>\n",
" function registerHandlebarHelperFunctions() {\n",
" //helper fun\n",
" function formatLabelDate(timestamp) {\n",
" const date = new Date(timestamp);\n",
" const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");\n",
" return format(date);\n",
" }\n",
"\n",
" function fixNumberTo(number, decimals = 3) {\n",
" return parseFloat(number).toFixed(decimals);\n",
" }\n",
"\n",
" const randomNumbers = (range) => Math.floor(Math.random() * range)\n",
"\n",
" const findFetureWithNumberSummary = (column) => {\n",
" const fetureIndex = Object.values(column.columns)\n",
" .findIndex((feture) => feture.numberSummary)\n",
"\n",
" return Object.keys(column.columns)[fetureIndex]\n",
" }\n",
"\n",
" const alertListItemStatus = (status, passedItem, failedItem) => {\n",
" if (status) {\n",
" return passedItem\n",
" } else {\n",
" return failedItem\n",
" }\n",
" }\n",
"\n",
" const alertListElement = (name, text, status, summary) => {\n",
" if (summary == null){\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="turquoise-background-color alert-tag">Passed</div>\n",
" `\n",
" ,\n",
" `\n",
" <div class="bordeaux-background-color alert-tag">Failed</div>\n",
" `\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
"\n",
" }\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="turquoise-background-color alert-tag">Passed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
"\n",
" ,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="bordeaux-background-color alert-tag">Failed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
" }\n",
"\n",
" let failedConstraints = 0;\n",
"\n",
" Handlebars.registerHelper("getProfileTimeStamp", function (column) {\n",
" return formatLabelDate(+column.properties.dataTimestamp)\n",
" });\n",
"\n",
" Handlebars.registerHelper("getProfileName", function (column) {\n",
" return column.properties.tags.name\n",
" });\n",
"\n",
"\n",
" Handlebars.registerHelper("alertLIst", function (column) {\n",
" let alertListItem = column.map((value) => {\n",
" if (value[1][0]) {\n",
" let alertListValue = value[1].map((cstr)=>{\n",
" return alertListElement(value[0],cstr[0],cstr[cstr.length - 1] === 0 || (failedConstraints++, false), value[3])\n",
" })\n",
" return alertListValue.join(' ')\n",
" } else {\n",
" return alertListElement('', value[0], value[2] === 0 || (failedConstraints++, false), value[3])\n",
" }\n",
" })\n",
" $(document).ready(() => {\n",
" $(".wl__feature-count--discrete").append(failedConstraints)\n",
" $(".wl__feature-count--non-discrete").append(column.length - failedConstraints)\n",
" $(".wl__feature-count--unknown").append(column.length)\n",
" })\n",
" return alertListItem.join(' ')\n",
" });\n",
"\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function initHandlebarsTemplate() {\n",
" // Replace this context with JSON from .py file\n",
" const context = [["weight greater than number 0.14", 0, 1, {"metric": "distribution", "mean": 2.3000011000000002, "stddev": 1.8560694154600064, "n": 5, "max": 4.3, "min": 5.5e-06, "q_01": 5.5e-06, "q_05": 5.5e-06, "q_10": 5.5e-06, "q_25": 1.3, "median": 1.8, "q_75": 4.1, "q_90": 4.3, "q_95": 4.3, "q_99": 4.3}], ["weight mean between 2 and 3 (inclusive)", 1, 0, {"metric": "distribution", "mean": 2.3000011000000002, "stddev": 1.8560694154600064, "n": 5, "max": 4.3, "min": 5.5e-06, "q_01": 5.5e-06, "q_05": 5.5e-06, "q_10": 5.5e-06, "q_25": 1.3, "median": 1.8, "q_75": 4.1, "q_90": 4.3, "q_95": 4.3, "q_99": 4.3}], ["weight smaller than number 20.5", 1, 0, {"metric": "distribution", "mean": 2.3000011000000002, "stddev": 1.8560694154600064, "n": 5, "max": 4.3, "min": 5.5e-06, "q_01": 5.5e-06, "q_05": 5.5e-06, "q_10": 5.5e-06, "q_25": 1.3, "median": 1.8, "q_75": 4.1, "q_90": 4.3, "q_95": 4.3, "q_99": 4.3}], ["weight standard deviation between 1 and 3 (inclusive)", 1, 0, {"metric": "distribution", "mean": 2.3000011000000002, "stddev": 1.8560694154600064, "n": 5, "max": 4.3, "min": 5.5e-06, "q_01": 5.5e-06, "q_05": 5.5e-06, "q_10": 5.5e-06, "q_25": 1.3, "median": 1.8, "q_75": 4.1, "q_90": 4.3, "q_95": 4.3, "q_99": 4.3}], ["weight 0.5-th quantile value between 1.5 and 2.0 (inclusive)", 1, 0, {"metric": "distribution", "mean": 2.3000011000000002, "stddev": 1.8560694154600064, "n": 5, "max": 4.3, "min": 5.5e-06, "q_01": 5.5e-06, "q_05": 5.5e-06, "q_10": 5.5e-06, "q_25": 1.3, "median": 1.8, "q_75": 4.1, "q_90": 4.3, "q_95": 4.3, "q_99": 4.3}], ["weight is in range [1.1,3.2]", 0, 1, {"metric": "distribution", "mean": 2.3000011000000002, "stddev": 1.8560694154600064, "n": 5, "max": 4.3, "min": 5.5e-06, "q_01": 5.5e-06, "q_05": 5.5e-06, "q_10": 5.5e-06, "q_25": 1.3, "median": 1.8, "q_75": 4.1, "q_90": 4.3, "q_95": 4.3, "q_99": 4.3}], ["legs is in range [0,6]", 1, 0, {"metric": "distribution", "mean": 3.2, "stddev": 2.280350850198276, "n": 5, "max": 6.0, "min": 0.0, "q_01": 0.0, "q_05": 0.0, "q_10": 0.0, "q_25": 2.0, "median": 4.0, "q_75": 4.0, "q_90": 6.0, "q_95": 6.0, "q_99": 6.0}], ["legs is non negative", 1, 0, {"metric": "distribution", "mean": 3.2, "stddev": 2.280350850198276, "n": 5, "max": 6.0, "min": 0.0, "q_01": 0.0, "q_05": 0.0, "q_10": 0.0, "q_25": 2.0, "median": 4.0, "q_75": 4.0, "q_90": 6.0, "q_95": 6.0, "q_99": 6.0}], ["animal 0.5-th quantile value between 1.5 and 2.0 (inclusive)", 0, 1, null]];\n",
" // Config handlebars and pass data to HBS template\n",
" const source = document.getElementById("entry-template").innerHTML;\n",
" const template = Handlebars.compile(source);\n",
" const html = template(context);\n",
" const target = document.getElementById("generated-html");\n",
" target.innerHTML = html;\n",
" }\n",
"\n",
" function initWebsiteScripts() {\n",
" const $featureSearch = document.getElementById("wl__feature-search");\n",
" const $alertList = document.getElementById("alert-list");\n",
" const $discrete = document.getElementById("inferredDiscrete");\n",
" const $nonDiscrete = document.getElementById("inferredNonDiscrete");\n",
" const $unknown = document.getElementById("inferredUnknown");\n",
"\n",
" const activeTypes = {\n",
" passed: true,\n",
" failed: true\n",
" };\n",
"\n",
" let searchString = "";\n",
"\n",
" function debounce(func, wait, immediate) {\n",
" let timeout;\n",
"\n",
" return function () {\n",
" const context = this;\n",
" const args = arguments;\n",
" const later = function () {\n",
" timeout = null;\n",
" if (!immediate) func.apply(context, args);\n",
" };\n",
"\n",
" const callNow = immediate && !timeout;\n",
" clearTimeout(timeout);\n",
" timeout = setTimeout(later, wait);\n",
" if (callNow) func.apply(context, args);\n",
" };\n",
" }\n",
"\n",
" function filterNotification() {\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const $boxes = $('.wl_filter-options>.form-check>input[name=checkbox]:checked');\n",
" const item = Object.values($boxes).find(function(value) { return $(value)[0] === undefined});\n",
" if (item === undefined) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" } else {\n",
" $notifCircleContainer.addClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function handleSearch() {\n",
" const tableBodyChildren = $alertList.children;\n",
"\n",
" for (let i = 0; i < tableBodyChildren.length; i++) {\n",
" const type = tableBodyChildren[i].dataset.inferredType.toLowerCase();\n",
" const name = $(tableBodyChildren[i].children[0]).html().toLowerCase();\n",
" if (activeTypes[type] && name.includes(searchString)) {\n",
" tableBodyChildren[i].style.display = "";\n",
" } else {\n",
" tableBodyChildren[i].style.display = "none";\n",
" }\n",
" }\n",
" }\n",
"\n",
" const checkedBoxes = () => {\n",
" if ($('.form-check-input:checked').length === $(".form-check-input").length - 1) {\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", true );\n",
" }\n",
" }\n",
"\n",
" $featureSearch.addEventListener(\n",
" "keyup",\n",
" debounce((event) => {\n",
" searchString = event.target.value.toLowerCase();\n",
" handleSearch();\n",
" }, 100),\n",
" );\n",
"\n",
" $discrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["failed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $nonDiscrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["passed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["passed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $unknown.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" $(".form-check-input").prop( "checked", true );\n",
" activeTypes["passed"] = true;\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" $(".form-check-input").prop( "checked", false );\n",
" activeTypes["passed"] = false;\n",
" activeTypes["failed"] = false;\n",
" }\n",
" handleSearch();\n",
" });\n",
" }\n",
"\n",
" function checkedBoxes() {\n",
" const $boxes = $('input[name=checkbox]:checked');\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
"\n",
" if ($boxes.length) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $notifCircleContainer.addClass("d-none")\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" checkedBoxes()\n",
" }\n",
" }\n",
"\n",
" // Invoke functions -- keep in mind invokation order\n",
" registerHandlebarHelperFunctions();\n",
" initHandlebarsTemplate();\n",
" initWebsiteScripts();\n",
" </script>\n",
"</html>\n",
"\" width=100% height=300\n",
" frameBorder=0></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"builder = ConstraintsBuilder(dataset_profile_view=profile_view)\n",
"builder.add_constraint(greater_than_number(column_name=\"weight\", number=0.14))\n",
"builder.add_constraint(mean_between_range(column_name=\"weight\", lower=2, upper=3))\n",
"builder.add_constraint(smaller_than_number(column_name=\"weight\", number=20.5))\n",
"builder.add_constraint(stddev_between_range(column_name=\"weight\", lower=1, upper=3))\n",
"builder.add_constraint(quantile_between_range(column_name=\"weight\", quantile=0.5, lower=1.5, upper=2.0))\n",
"builder.add_constraint(is_in_range(column_name=\"weight\", lower=1.1, upper=3.2))\n",
"builder.add_constraint(is_in_range(column_name=\"legs\", lower=0, upper=6))\n",
"builder.add_constraint(is_non_negative(column_name=\"legs\"))\n",
"\n",
"# animal has missing distribution metrics. this will pass if skip_missing = True and fail otherwise.\n",
"builder.add_constraint(\n",
" quantile_between_range(\n",
" column_name=\"animal\", \n",
" quantile=0.5, \n",
" lower=1.5, \n",
" upper=2.0, \n",
" skip_missing=False\n",
" )\n",
")\n",
"\n",
"constraints = builder.build()\n",
"\n",
"from whylogs.viz import NotebookProfileVisualizer\n",
"\n",
"visualization = NotebookProfileVisualizer()\n",
"visualization.constraints_report(constraints, cell_height=300)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Frequent Items/Frequent Strings Constraints <a class=\"anchor\" id=\"frequent\"></a>"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"from whylogs.core.constraints.factories import n_most_common_items_in_set, frequent_strings_in_reference_set"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples - Frequent Items/Frequent Strings Constraints"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"import whylogs as why\n",
"import pandas as pd\n",
"data = {\n",
" \"animal\": [\"cat\", \"snake\", \"snake\", \"cat\", \"mosquito\"],\n",
" \"legs\": [0, 1, 2, 3, 4],\n",
" \"weight\": [4.3, 1.8, 1.3, 4.1, 5.5e-6],\n",
"}\n",
"\n",
"results = why.log(pd.DataFrame(data))\n",
"profile_view = results.view()"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div></div><iframe srcdoc=\"<!DOCTYPE html>\n",
"<html lang="en">\n",
" <head>\n",
" <meta charset="UTF-8" />\n",
" <meta http-equiv="X-UA-Compatible" content="IE=edge" />\n",
" <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n",
" <meta name="description" content="" />\n",
" <meta name="author" content="" />\n",
"\n",
" <title>Profile Visualizer | whylogs</title>\n",
"\n",
" <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />\n",
" <link rel="preconnect" href="https://fonts.googleapis.com" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n",
" <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" />\n",
" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />\n",
"\n",
" <script\n",
" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"\n",
" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="\n",
" crossorigin="anonymous"\n",
" referrerpolicy="no-referrer"\n",
" ></script>\n",
"\n",
" <style type="text/css">\n",
"\n",
" /* Screen on smaller screens */\n",
" .no-responsive {\n",
" display: none;\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1031;\n",
" width: 100vw;\n",
" height: 100vh;\n",
" background-color: var(--tealBackground);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" }\n",
"\n",
" @media screen and (min-width: 1000px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
"\n",
" .no-responsive__content {\n",
" max-width: 600px;\n",
" width: 100%;\n",
" padding: 0 24px;\n",
" }\n",
"\n",
" .no-responsive__title {\n",
" font-size: 96px;\n",
" font-weight: 300;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.167;\n",
" }\n",
"\n",
" .no-responsive__text {\n",
" margin: 0;\n",
" font-size: 16px;\n",
" font-weight: 400;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.5;\n",
" }\n",
"\n",
" .header-title {\n",
" font-size: 26px;\n",
" font-weight: 700;\n",
" color: #444444;\n",
" }\n",
"\n",
" .tooltip-full-number {\n",
" position: relative;\n",
" display: inline-block;\n",
" }\n",
"\n",
" .tooltip-full-number .tooltiptext {\n",
" visibility: hidden;\n",
" background: black;\n",
" color: white;\n",
" border: 1px solid black;\n",
" text-align: start;\n",
" padding: 3px;\n",
" position: absolute;\n",
" z-index: 1;\n",
" top: 0;\n",
" left: 100%;\n",
" margin-left: 5px;\n",
" opacity: 0;\n",
" transition: opacity 0.5s;\n",
" font-size: 13px;\n",
" font-weight: normal;\n",
" line-height: 100%;\n",
" }\n",
"\n",
" .tooltip-full-number:hover .tooltiptext {\n",
" visibility: visible;\n",
" opacity: 1;\n",
" }\n",
"\n",
"\n",
" .wl-compare-profile {\n",
" position: relative;\n",
" left: 0;\n",
" padding: 30px;\n",
" margin-bottom: 20px;\n",
" background: var(--white);;\n",
" border-bottom: 1px solid #CED4DA;\n",
" }\n",
"\n",
" .alert-list {\n",
" padding: 30px;\n",
" padding-top: 0;\n",
" }\n",
"\n",
" .drift-detection {\n",
" justify-content: space-between;\n",
" align-items: center;\n",
" }\n",
"\n",
" .drift-detection-info-circle {\n",
" width: 15px;\n",
" height: 15px;\n",
" border-radius: 50px;\n",
" display: inline-block;\n",
" margin-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item {\n",
" padding-right: 20px;\n",
" }\n",
"\n",
" .drift-detection-info-title {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 22px;\n",
" line-height: 130%;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-count {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 14px;\n",
" line-height: 16px;\n",
" color: #000000;\n",
" padding-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-name {\n",
" font-family: Arial;\n",
" font-style: normal;\n",
" font-weight: normal;\n",
" font-size: 12px;\n",
" line-height: 14px;\n",
" color: #000000;\n",
" }\n",
"\n",
" .drift-detection-search-input {\n",
" display: flex;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 170px;\n",
" padding-left: 10px;\n",
" }\n",
"\n",
" .drift-detection-search-input img{\n",
" margin-right: 5px;\n",
" }\n",
"\n",
" .drift-detection-search-input input::placeholder {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 13px;\n",
" line-height: 16px;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .dropdown-container {\n",
" position: absolute;\n",
" right: 30px;\n",
" top: 80px;\n",
" z-index: 999;\n",
" background: #FFFFFF;\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.05);\n",
" border-radius: 4px;\n",
" padding: 10px !important;\n",
" border: none !important;\n",
" }\n",
"\n",
" .filter-options-title {\n",
" width: 240px;\n",
" }\n",
"\n",
" .filter-options-title p {\n",
" margin: 0;\n",
" }\n",
"\n",
" .form-check-input:checked {\n",
" background-color: #0E7384;\n",
" border-color: #0E7384;\n",
" }\n",
"\n",
" .form-check-input[type=checkbox] {\n",
" border-radius: 2px;\n",
" }\n",
"\n",
" .search-input{\n",
" padding-top: 0 !important;\n",
" padding-bottom: 0 !important;\n",
" }\n",
"\n",
" .search-input input{\n",
" border: none;\n",
" background: none;\n",
" outline: none;\n",
" height: 40px;\n",
" width: 100%;\n",
" font-size: 14px;\n",
" }\n",
"\n",
" .search-input img{\n",
" height: 19px;\n",
" pointer-events: none;\n",
" }\n",
"\n",
" input::placeholder {\n",
" color: var(--secondaryLight1000);\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .close-filter-button {\n",
" display: flex;\n",
" justify-content: center;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #369BAC;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 40px;\n",
" height: 40px;\n",
" cursor: pointer;\n",
" margin-left: 10px;\n",
" }\n",
"\n",
" .statistic-number-title {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 20px;\n",
" color: #6C757D;\n",
" }\n",
"\n",
" .statistic-number {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 20px;\n",
" line-height: 140%;\n",
" display: flex;\n",
" align-items: center;\n",
" color: #4F595B;\n",
" }\n",
"\n",
" .full-summary-statistics-wrap {\n",
" padding: 20px;\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .statistics-list {\n",
" width: 100% ;\n",
" }\n",
"\n",
" mark {\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 140%;\n",
" }\n",
"\n",
" .blue-mark {\n",
" background-color: #369BAC1A;\n",
" color: #369BAC;\n",
" }\n",
"\n",
" .red-mark {\n",
" background-color: #FFEFEE;\n",
" color: #F5473C;\n",
" }\n",
"\n",
" .alert-tag {\n",
" height: 27px;\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 12px;\n",
" line-height: 140%;\n",
" color: #FFFFFF;\n",
" }\n",
"\n",
" .turquoise-background-color {\n",
" background-color: #1DBB42;\n",
" }\n",
"\n",
" .bordeaux-background-color {\n",
" background-color: #C6462A;\n",
" }\n",
"\n",
" .border-solid-gray {\n",
" border: 1px solid #CED4DA;\n",
" border-radius: 4px;\n",
" }\n",
"\n",
" .display-flex {\n",
" display: flex;\n",
" }\n",
"\n",
" .justify-content-space-between {\n",
" justify-content: space-between;\n",
" }\n",
"\n",
" .justify-content-center {\n",
" justify-content: center;\n",
" }\n",
"\n",
" .align-items-center {\n",
" align-items: center;\n",
" }\n",
"\n",
" .align-items-flex-start {\n",
" align-items: flex-start;\n",
" }\n",
"\n",
" .padding-right-30 {\n",
" padding-right: 30px;\n",
" }\n",
"\n",
" .notif-circle-container{\n",
" position: absolute;\n",
" top: 25px;\n",
" right: 25px;\n",
" padding: 5.3px;\n",
" border-radius: 50%;\n",
" background-color: white;\n",
" cursor: pointer;\n",
" }\n",
"\n",
" .notif-circle {\n",
" position: absolute;\n",
" top: 2px;\n",
" right: 2px;\n",
" padding: 3.3px;\n",
" border-radius: 50%;\n",
" background-color: #F2994A;\n",
" }\n",
"\n",
" .alert-list-text {\n",
" width: 70%\n",
" }\n",
"\n",
" @media screen and (min-width: 500px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
" </style>\n",
" </head>\n",
"\n",
" <body id="generated-html"></body>\n",
"\n",
" <script id="entry-template" type="text/x-handlebars-template">\n",
" \n",
" <div class="desktop-content">\n",
" <div class="full-summary-statistics-wrap">\n",
" <div class="full-summary-statistics">\n",
" <div>\n",
" <div class="display-flex justify-content-center">\n",
" <div class="statistics-list border-solid-gray">\n",
" <div>\n",
" <div class="wl-compare-profile" id="compare-profile">\n",
" <div class="drift-detection-wrap">\n",
" <div class="drift-detection display-flex align-items-flex-start">\n",
" <div class="drift-detection-info flex-direction-colum">\n",
" <div class="drift-detection-info-title-wrap display-flex">\n",
" <p class="drift-detection-info-title">\n",
" Constraints Report\n",
" </p>\n",
" </div>\n",
"\n",
" <!-- </div> -->\n",
" </div>\n",
" <div class="drift-detection-search-input-wrap display-flex">\n",
" <div class="drift-detection-search-input search-input">\n",
" <input type="text" id="wl__feature-search" placeholder="Quick search..."/>\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGdSURBVHgBpZK7TkJBEIZnZoVocdTYyQNALxpNKPQBMEaNJsbCRMKhl8ISWwt6AaksCF5iTHgAGhJD4AHkAaAzGiwUsjvOQnO4SYh/cXbPzO43OxcEj9Zy92EiFSXNIfvPyE1kKFfdoxJMENpP6DrvLC0vJoEwCgwto7DWcxoIIHBYbA3NmKwnDltjAeuZhyul1DaTTlfPB6Nt5Z53DOgky4P875+nlctY2+unjZviLklkJhi5bPUa3y/7qJuQUM7PinMy7CdQc1Gh16vnBxPzrMROmlKQEgKNASAHLQCmSIGpS75O+O5pdQAgVXaIqTkNwDDXHmcnW3VmHZoGMLoTsOt88+NrAMCIZdu+iLTyTwKRa1Md6YKfOgXbzO7K8sWku5u5RxcRV5EpPezrzcHGbXEXWaUkgkweZ/UC9YrK3zqggFw5FBZfm8EUavHj7AjAKpIvBDrGn+pNnlcyhYgqbcC41idr1gvB4SdZkDbzQa21gwv0Vj07aPTtL07XdDOyDXohCDNoHIRmAVRie20f+RKybRDQDvxHkXy/7b/DrayncLbMwQAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="wl__dropdown_arrow-icon">\n",
" <div onclick="openFilter()" class="close-filter-button">\n",
" <div class="display-flex close-filter-icon d-none">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADFSURBVHgBfY+xDcIwEEXvnLQBZQkYAEhDwwKpEEK0CCZgAEjJCEmgjYSAygxAHTZgFRSOsyUjY5mcZFnn/+78PwBXf3+MoKWUPuYjVBPFnTwpr9t/oNJfcTfXsAhRAlDqDhhQIPYgpAqNMDqcUqSAYZT1epr9gAHt6uXshvYme4DYHQJNDKh0dD0m5WXB10Y3Fqjtuh7fROn3oREDWxfeMLyRsMnc0OgDzdduaA0Pi3Plgr7Q2kaAePeBqh6rueSNBVt6fgCwBV1JLF3rlAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="display-flex filter-icon">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACSSURBVHgBrZLBCYAwDEWTUjw7igcdwI1cxkNXUJzBEVzFAbSVKoKmaVrEB6GHJv/w+AACtRk7P9IONv1QOYUl96k0zv61m2tjARoLtSDI3EFsgIJ4uoXrMLazO72CRG2mzg/8BSdVlEjhpGZJjAWdAZJECpWalEhJSs1pHuUlMad5FFai1Lwg4Ckx1TxKIPFL8w55mEWd8VjPGAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" </div>\n",
" <span class="notif-circle-container">\n",
" <span class="notif-circle"></span>\n",
" </span>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="dropdown-container flex-direction-colum mb-2 d-none" id="dropdown-container">\n",
" <div class="filter-options">\n",
" <div class="filter-options-title space-between dropdown">\n",
" <p>Select a view:</p>\n",
" </div>\n",
" <div class="form-check mb-1 mt-2">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Discrete"\n",
" id="inferredDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredDiscrete">\n",
" Failed constraints (<span class="wl__feature-count--discrete"></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Non-discrete"\n",
" id="inferredNonDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredNonDiscrete">\n",
" Passed constraints (<span\n",
" class="wl__feature-count--non-discrete"\n",
" ></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Unknown"\n",
" id="inferredUnknown"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredUnknown">\n",
" All constraints (<span class="wl__feature-count--unknown"></span>)\n",
" </label>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="alert-list" id="alert-list">\n",
" {{{alertLIst this}}}\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="no-responsive">\n",
" <div class="no-responsive__content">\n",
" <h1 class="no-responsive__title">Hold on! :)</h1>\n",
" <p class="no-responsive__text">\n",
" It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is\n",
" best experienced on a desktop computer. Please try maximizing this window or switching to another device. We\n",
" are working on adding support for a larger variety of devices.\n",
" </p>\n",
" </div>\n",
" </div>\n",
" \n",
" </script>\n",
"\n",
" <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>\n",
"\n",
" <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n",
"\n",
" <script>\n",
" function registerHandlebarHelperFunctions() {\n",
" //helper fun\n",
" function formatLabelDate(timestamp) {\n",
" const date = new Date(timestamp);\n",
" const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");\n",
" return format(date);\n",
" }\n",
"\n",
" function fixNumberTo(number, decimals = 3) {\n",
" return parseFloat(number).toFixed(decimals);\n",
" }\n",
"\n",
" const randomNumbers = (range) => Math.floor(Math.random() * range)\n",
"\n",
" const findFetureWithNumberSummary = (column) => {\n",
" const fetureIndex = Object.values(column.columns)\n",
" .findIndex((feture) => feture.numberSummary)\n",
"\n",
" return Object.keys(column.columns)[fetureIndex]\n",
" }\n",
"\n",
" const alertListItemStatus = (status, passedItem, failedItem) => {\n",
" if (status) {\n",
" return passedItem\n",
" } else {\n",
" return failedItem\n",
" }\n",
" }\n",
"\n",
" const alertListElement = (name, text, status, summary) => {\n",
" if (summary == null){\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="turquoise-background-color alert-tag">Passed</div>\n",
" `\n",
" ,\n",
" `\n",
" <div class="bordeaux-background-color alert-tag">Failed</div>\n",
" `\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
"\n",
" }\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="turquoise-background-color alert-tag">Passed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
"\n",
" ,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="bordeaux-background-color alert-tag">Failed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
" }\n",
"\n",
" let failedConstraints = 0;\n",
"\n",
" Handlebars.registerHelper("getProfileTimeStamp", function (column) {\n",
" return formatLabelDate(+column.properties.dataTimestamp)\n",
" });\n",
"\n",
" Handlebars.registerHelper("getProfileName", function (column) {\n",
" return column.properties.tags.name\n",
" });\n",
"\n",
"\n",
" Handlebars.registerHelper("alertLIst", function (column) {\n",
" let alertListItem = column.map((value) => {\n",
" if (value[1][0]) {\n",
" let alertListValue = value[1].map((cstr)=>{\n",
" return alertListElement(value[0],cstr[0],cstr[cstr.length - 1] === 0 || (failedConstraints++, false), value[3])\n",
" })\n",
" return alertListValue.join(' ')\n",
" } else {\n",
" return alertListElement('', value[0], value[2] === 0 || (failedConstraints++, false), value[3])\n",
" }\n",
" })\n",
" $(document).ready(() => {\n",
" $(".wl__feature-count--discrete").append(failedConstraints)\n",
" $(".wl__feature-count--non-discrete").append(column.length - failedConstraints)\n",
" $(".wl__feature-count--unknown").append(column.length)\n",
" })\n",
" return alertListItem.join(' ')\n",
" });\n",
"\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function initHandlebarsTemplate() {\n",
" // Replace this context with JSON from .py file\n",
" const context = [["animal values in set {'snake', 'cat'}", 0, 1, {"metric": "frequent_items", "frequent_strings_top_10": ["cat:2", "snake:2", "mosquito:1"]}], ["animal 2-most common items in set {'snake', 'cat'}", 1, 0, {"metric": "frequent_items", "frequent_strings_top_10": ["cat:2", "snake:2", "mosquito:1"]}]];\n",
" // Config handlebars and pass data to HBS template\n",
" const source = document.getElementById("entry-template").innerHTML;\n",
" const template = Handlebars.compile(source);\n",
" const html = template(context);\n",
" const target = document.getElementById("generated-html");\n",
" target.innerHTML = html;\n",
" }\n",
"\n",
" function initWebsiteScripts() {\n",
" const $featureSearch = document.getElementById("wl__feature-search");\n",
" const $alertList = document.getElementById("alert-list");\n",
" const $discrete = document.getElementById("inferredDiscrete");\n",
" const $nonDiscrete = document.getElementById("inferredNonDiscrete");\n",
" const $unknown = document.getElementById("inferredUnknown");\n",
"\n",
" const activeTypes = {\n",
" passed: true,\n",
" failed: true\n",
" };\n",
"\n",
" let searchString = "";\n",
"\n",
" function debounce(func, wait, immediate) {\n",
" let timeout;\n",
"\n",
" return function () {\n",
" const context = this;\n",
" const args = arguments;\n",
" const later = function () {\n",
" timeout = null;\n",
" if (!immediate) func.apply(context, args);\n",
" };\n",
"\n",
" const callNow = immediate && !timeout;\n",
" clearTimeout(timeout);\n",
" timeout = setTimeout(later, wait);\n",
" if (callNow) func.apply(context, args);\n",
" };\n",
" }\n",
"\n",
" function filterNotification() {\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const $boxes = $('.wl_filter-options>.form-check>input[name=checkbox]:checked');\n",
" const item = Object.values($boxes).find(function(value) { return $(value)[0] === undefined});\n",
" if (item === undefined) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" } else {\n",
" $notifCircleContainer.addClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function handleSearch() {\n",
" const tableBodyChildren = $alertList.children;\n",
"\n",
" for (let i = 0; i < tableBodyChildren.length; i++) {\n",
" const type = tableBodyChildren[i].dataset.inferredType.toLowerCase();\n",
" const name = $(tableBodyChildren[i].children[0]).html().toLowerCase();\n",
" if (activeTypes[type] && name.includes(searchString)) {\n",
" tableBodyChildren[i].style.display = "";\n",
" } else {\n",
" tableBodyChildren[i].style.display = "none";\n",
" }\n",
" }\n",
" }\n",
"\n",
" const checkedBoxes = () => {\n",
" if ($('.form-check-input:checked').length === $(".form-check-input").length - 1) {\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", true );\n",
" }\n",
" }\n",
"\n",
" $featureSearch.addEventListener(\n",
" "keyup",\n",
" debounce((event) => {\n",
" searchString = event.target.value.toLowerCase();\n",
" handleSearch();\n",
" }, 100),\n",
" );\n",
"\n",
" $discrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["failed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $nonDiscrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["passed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["passed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $unknown.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" $(".form-check-input").prop( "checked", true );\n",
" activeTypes["passed"] = true;\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" $(".form-check-input").prop( "checked", false );\n",
" activeTypes["passed"] = false;\n",
" activeTypes["failed"] = false;\n",
" }\n",
" handleSearch();\n",
" });\n",
" }\n",
"\n",
" function checkedBoxes() {\n",
" const $boxes = $('input[name=checkbox]:checked');\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
"\n",
" if ($boxes.length) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $notifCircleContainer.addClass("d-none")\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" checkedBoxes()\n",
" }\n",
" }\n",
"\n",
" // Invoke functions -- keep in mind invokation order\n",
" registerHandlebarHelperFunctions();\n",
" initHandlebarsTemplate();\n",
" initWebsiteScripts();\n",
" </script>\n",
"</html>\n",
"\" width=100% height=300\n",
" frameBorder=0></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"builder = ConstraintsBuilder(dataset_profile_view=profile_view)\n",
"reference_set = {\"cat\",\"snake\"}\n",
"builder.add_constraint(frequent_strings_in_reference_set(column_name=\"animal\", reference_set=reference_set))\n",
"builder.add_constraint(n_most_common_items_in_set(column_name=\"animal\",n=2,reference_set=reference_set))\n",
"\n",
"constraints = builder.build()\n",
"\n",
"from whylogs.viz import NotebookProfileVisualizer\n",
"\n",
"visualization = NotebookProfileVisualizer()\n",
"visualization.constraints_report(constraints, cell_height=300)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Counters Constraints <a class=\"anchor\" id=\"counts\"></a>"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"from whylogs.core.constraints.factories import no_missing_values, count_below_number, null_percentage_below_number, null_values_below_number"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples - Counters Constraints"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"import whylogs as why\n",
"import pandas as pd\n",
"data = {\n",
" \"animal\": [\"cat\", \"snake\", \"snake\", \"cat\", \"mosquito\"],\n",
" \"legs\": [4, 2, 0, None, 6],\n",
" \"weight\": [4.3, 1.8, 1.3, 4.1, 5.5e-6],\n",
"}\n",
"\n",
"results = why.log(pd.DataFrame(data))\n",
"profile_view = results.view()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div></div><iframe srcdoc=\"<!DOCTYPE html>\n",
"<html lang="en">\n",
" <head>\n",
" <meta charset="UTF-8" />\n",
" <meta http-equiv="X-UA-Compatible" content="IE=edge" />\n",
" <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n",
" <meta name="description" content="" />\n",
" <meta name="author" content="" />\n",
"\n",
" <title>Profile Visualizer | whylogs</title>\n",
"\n",
" <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />\n",
" <link rel="preconnect" href="https://fonts.googleapis.com" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n",
" <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" />\n",
" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />\n",
"\n",
" <script\n",
" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"\n",
" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="\n",
" crossorigin="anonymous"\n",
" referrerpolicy="no-referrer"\n",
" ></script>\n",
"\n",
" <style type="text/css">\n",
"\n",
" /* Screen on smaller screens */\n",
" .no-responsive {\n",
" display: none;\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1031;\n",
" width: 100vw;\n",
" height: 100vh;\n",
" background-color: var(--tealBackground);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" }\n",
"\n",
" @media screen and (min-width: 1000px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
"\n",
" .no-responsive__content {\n",
" max-width: 600px;\n",
" width: 100%;\n",
" padding: 0 24px;\n",
" }\n",
"\n",
" .no-responsive__title {\n",
" font-size: 96px;\n",
" font-weight: 300;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.167;\n",
" }\n",
"\n",
" .no-responsive__text {\n",
" margin: 0;\n",
" font-size: 16px;\n",
" font-weight: 400;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.5;\n",
" }\n",
"\n",
" .header-title {\n",
" font-size: 26px;\n",
" font-weight: 700;\n",
" color: #444444;\n",
" }\n",
"\n",
" .tooltip-full-number {\n",
" position: relative;\n",
" display: inline-block;\n",
" }\n",
"\n",
" .tooltip-full-number .tooltiptext {\n",
" visibility: hidden;\n",
" background: black;\n",
" color: white;\n",
" border: 1px solid black;\n",
" text-align: start;\n",
" padding: 3px;\n",
" position: absolute;\n",
" z-index: 1;\n",
" top: 0;\n",
" left: 100%;\n",
" margin-left: 5px;\n",
" opacity: 0;\n",
" transition: opacity 0.5s;\n",
" font-size: 13px;\n",
" font-weight: normal;\n",
" line-height: 100%;\n",
" }\n",
"\n",
" .tooltip-full-number:hover .tooltiptext {\n",
" visibility: visible;\n",
" opacity: 1;\n",
" }\n",
"\n",
"\n",
" .wl-compare-profile {\n",
" position: relative;\n",
" left: 0;\n",
" padding: 30px;\n",
" margin-bottom: 20px;\n",
" background: var(--white);;\n",
" border-bottom: 1px solid #CED4DA;\n",
" }\n",
"\n",
" .alert-list {\n",
" padding: 30px;\n",
" padding-top: 0;\n",
" }\n",
"\n",
" .drift-detection {\n",
" justify-content: space-between;\n",
" align-items: center;\n",
" }\n",
"\n",
" .drift-detection-info-circle {\n",
" width: 15px;\n",
" height: 15px;\n",
" border-radius: 50px;\n",
" display: inline-block;\n",
" margin-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item {\n",
" padding-right: 20px;\n",
" }\n",
"\n",
" .drift-detection-info-title {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 22px;\n",
" line-height: 130%;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-count {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 14px;\n",
" line-height: 16px;\n",
" color: #000000;\n",
" padding-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-name {\n",
" font-family: Arial;\n",
" font-style: normal;\n",
" font-weight: normal;\n",
" font-size: 12px;\n",
" line-height: 14px;\n",
" color: #000000;\n",
" }\n",
"\n",
" .drift-detection-search-input {\n",
" display: flex;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 170px;\n",
" padding-left: 10px;\n",
" }\n",
"\n",
" .drift-detection-search-input img{\n",
" margin-right: 5px;\n",
" }\n",
"\n",
" .drift-detection-search-input input::placeholder {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 13px;\n",
" line-height: 16px;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .dropdown-container {\n",
" position: absolute;\n",
" right: 30px;\n",
" top: 80px;\n",
" z-index: 999;\n",
" background: #FFFFFF;\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.05);\n",
" border-radius: 4px;\n",
" padding: 10px !important;\n",
" border: none !important;\n",
" }\n",
"\n",
" .filter-options-title {\n",
" width: 240px;\n",
" }\n",
"\n",
" .filter-options-title p {\n",
" margin: 0;\n",
" }\n",
"\n",
" .form-check-input:checked {\n",
" background-color: #0E7384;\n",
" border-color: #0E7384;\n",
" }\n",
"\n",
" .form-check-input[type=checkbox] {\n",
" border-radius: 2px;\n",
" }\n",
"\n",
" .search-input{\n",
" padding-top: 0 !important;\n",
" padding-bottom: 0 !important;\n",
" }\n",
"\n",
" .search-input input{\n",
" border: none;\n",
" background: none;\n",
" outline: none;\n",
" height: 40px;\n",
" width: 100%;\n",
" font-size: 14px;\n",
" }\n",
"\n",
" .search-input img{\n",
" height: 19px;\n",
" pointer-events: none;\n",
" }\n",
"\n",
" input::placeholder {\n",
" color: var(--secondaryLight1000);\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .close-filter-button {\n",
" display: flex;\n",
" justify-content: center;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #369BAC;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 40px;\n",
" height: 40px;\n",
" cursor: pointer;\n",
" margin-left: 10px;\n",
" }\n",
"\n",
" .statistic-number-title {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 20px;\n",
" color: #6C757D;\n",
" }\n",
"\n",
" .statistic-number {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 20px;\n",
" line-height: 140%;\n",
" display: flex;\n",
" align-items: center;\n",
" color: #4F595B;\n",
" }\n",
"\n",
" .full-summary-statistics-wrap {\n",
" padding: 20px;\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .statistics-list {\n",
" width: 100% ;\n",
" }\n",
"\n",
" mark {\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 140%;\n",
" }\n",
"\n",
" .blue-mark {\n",
" background-color: #369BAC1A;\n",
" color: #369BAC;\n",
" }\n",
"\n",
" .red-mark {\n",
" background-color: #FFEFEE;\n",
" color: #F5473C;\n",
" }\n",
"\n",
" .alert-tag {\n",
" height: 27px;\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 12px;\n",
" line-height: 140%;\n",
" color: #FFFFFF;\n",
" }\n",
"\n",
" .turquoise-background-color {\n",
" background-color: #1DBB42;\n",
" }\n",
"\n",
" .bordeaux-background-color {\n",
" background-color: #C6462A;\n",
" }\n",
"\n",
" .border-solid-gray {\n",
" border: 1px solid #CED4DA;\n",
" border-radius: 4px;\n",
" }\n",
"\n",
" .display-flex {\n",
" display: flex;\n",
" }\n",
"\n",
" .justify-content-space-between {\n",
" justify-content: space-between;\n",
" }\n",
"\n",
" .justify-content-center {\n",
" justify-content: center;\n",
" }\n",
"\n",
" .align-items-center {\n",
" align-items: center;\n",
" }\n",
"\n",
" .align-items-flex-start {\n",
" align-items: flex-start;\n",
" }\n",
"\n",
" .padding-right-30 {\n",
" padding-right: 30px;\n",
" }\n",
"\n",
" .notif-circle-container{\n",
" position: absolute;\n",
" top: 25px;\n",
" right: 25px;\n",
" padding: 5.3px;\n",
" border-radius: 50%;\n",
" background-color: white;\n",
" cursor: pointer;\n",
" }\n",
"\n",
" .notif-circle {\n",
" position: absolute;\n",
" top: 2px;\n",
" right: 2px;\n",
" padding: 3.3px;\n",
" border-radius: 50%;\n",
" background-color: #F2994A;\n",
" }\n",
"\n",
" .alert-list-text {\n",
" width: 70%\n",
" }\n",
"\n",
" @media screen and (min-width: 500px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
" </style>\n",
" </head>\n",
"\n",
" <body id="generated-html"></body>\n",
"\n",
" <script id="entry-template" type="text/x-handlebars-template">\n",
" \n",
" <div class="desktop-content">\n",
" <div class="full-summary-statistics-wrap">\n",
" <div class="full-summary-statistics">\n",
" <div>\n",
" <div class="display-flex justify-content-center">\n",
" <div class="statistics-list border-solid-gray">\n",
" <div>\n",
" <div class="wl-compare-profile" id="compare-profile">\n",
" <div class="drift-detection-wrap">\n",
" <div class="drift-detection display-flex align-items-flex-start">\n",
" <div class="drift-detection-info flex-direction-colum">\n",
" <div class="drift-detection-info-title-wrap display-flex">\n",
" <p class="drift-detection-info-title">\n",
" Constraints Report\n",
" </p>\n",
" </div>\n",
"\n",
" <!-- </div> -->\n",
" </div>\n",
" <div class="drift-detection-search-input-wrap display-flex">\n",
" <div class="drift-detection-search-input search-input">\n",
" <input type="text" id="wl__feature-search" placeholder="Quick search..."/>\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGdSURBVHgBpZK7TkJBEIZnZoVocdTYyQNALxpNKPQBMEaNJsbCRMKhl8ISWwt6AaksCF5iTHgAGhJD4AHkAaAzGiwUsjvOQnO4SYh/cXbPzO43OxcEj9Zy92EiFSXNIfvPyE1kKFfdoxJMENpP6DrvLC0vJoEwCgwto7DWcxoIIHBYbA3NmKwnDltjAeuZhyul1DaTTlfPB6Nt5Z53DOgky4P875+nlctY2+unjZviLklkJhi5bPUa3y/7qJuQUM7PinMy7CdQc1Gh16vnBxPzrMROmlKQEgKNASAHLQCmSIGpS75O+O5pdQAgVXaIqTkNwDDXHmcnW3VmHZoGMLoTsOt88+NrAMCIZdu+iLTyTwKRa1Md6YKfOgXbzO7K8sWku5u5RxcRV5EpPezrzcHGbXEXWaUkgkweZ/UC9YrK3zqggFw5FBZfm8EUavHj7AjAKpIvBDrGn+pNnlcyhYgqbcC41idr1gvB4SdZkDbzQa21gwv0Vj07aPTtL07XdDOyDXohCDNoHIRmAVRie20f+RKybRDQDvxHkXy/7b/DrayncLbMwQAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="wl__dropdown_arrow-icon">\n",
" <div onclick="openFilter()" class="close-filter-button">\n",
" <div class="display-flex close-filter-icon d-none">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADFSURBVHgBfY+xDcIwEEXvnLQBZQkYAEhDwwKpEEK0CCZgAEjJCEmgjYSAygxAHTZgFRSOsyUjY5mcZFnn/+78PwBXf3+MoKWUPuYjVBPFnTwpr9t/oNJfcTfXsAhRAlDqDhhQIPYgpAqNMDqcUqSAYZT1epr9gAHt6uXshvYme4DYHQJNDKh0dD0m5WXB10Y3Fqjtuh7fROn3oREDWxfeMLyRsMnc0OgDzdduaA0Pi3Plgr7Q2kaAePeBqh6rueSNBVt6fgCwBV1JLF3rlAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="display-flex filter-icon">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACSSURBVHgBrZLBCYAwDEWTUjw7igcdwI1cxkNXUJzBEVzFAbSVKoKmaVrEB6GHJv/w+AACtRk7P9IONv1QOYUl96k0zv61m2tjARoLtSDI3EFsgIJ4uoXrMLazO72CRG2mzg/8BSdVlEjhpGZJjAWdAZJECpWalEhJSs1pHuUlMad5FFai1Lwg4Ckx1TxKIPFL8w55mEWd8VjPGAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" </div>\n",
" <span class="notif-circle-container">\n",
" <span class="notif-circle"></span>\n",
" </span>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="dropdown-container flex-direction-colum mb-2 d-none" id="dropdown-container">\n",
" <div class="filter-options">\n",
" <div class="filter-options-title space-between dropdown">\n",
" <p>Select a view:</p>\n",
" </div>\n",
" <div class="form-check mb-1 mt-2">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Discrete"\n",
" id="inferredDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredDiscrete">\n",
" Failed constraints (<span class="wl__feature-count--discrete"></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Non-discrete"\n",
" id="inferredNonDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredNonDiscrete">\n",
" Passed constraints (<span\n",
" class="wl__feature-count--non-discrete"\n",
" ></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Unknown"\n",
" id="inferredUnknown"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredUnknown">\n",
" All constraints (<span class="wl__feature-count--unknown"></span>)\n",
" </label>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="alert-list" id="alert-list">\n",
" {{{alertLIst this}}}\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="no-responsive">\n",
" <div class="no-responsive__content">\n",
" <h1 class="no-responsive__title">Hold on! :)</h1>\n",
" <p class="no-responsive__text">\n",
" It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is\n",
" best experienced on a desktop computer. Please try maximizing this window or switching to another device. We\n",
" are working on adding support for a larger variety of devices.\n",
" </p>\n",
" </div>\n",
" </div>\n",
" \n",
" </script>\n",
"\n",
" <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>\n",
"\n",
" <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n",
"\n",
" <script>\n",
" function registerHandlebarHelperFunctions() {\n",
" //helper fun\n",
" function formatLabelDate(timestamp) {\n",
" const date = new Date(timestamp);\n",
" const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");\n",
" return format(date);\n",
" }\n",
"\n",
" function fixNumberTo(number, decimals = 3) {\n",
" return parseFloat(number).toFixed(decimals);\n",
" }\n",
"\n",
" const randomNumbers = (range) => Math.floor(Math.random() * range)\n",
"\n",
" const findFetureWithNumberSummary = (column) => {\n",
" const fetureIndex = Object.values(column.columns)\n",
" .findIndex((feture) => feture.numberSummary)\n",
"\n",
" return Object.keys(column.columns)[fetureIndex]\n",
" }\n",
"\n",
" const alertListItemStatus = (status, passedItem, failedItem) => {\n",
" if (status) {\n",
" return passedItem\n",
" } else {\n",
" return failedItem\n",
" }\n",
" }\n",
"\n",
" const alertListElement = (name, text, status, summary) => {\n",
" if (summary == null){\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="turquoise-background-color alert-tag">Passed</div>\n",
" `\n",
" ,\n",
" `\n",
" <div class="bordeaux-background-color alert-tag">Failed</div>\n",
" `\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
"\n",
" }\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="turquoise-background-color alert-tag">Passed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
"\n",
" ,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="bordeaux-background-color alert-tag">Failed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
" }\n",
"\n",
" let failedConstraints = 0;\n",
"\n",
" Handlebars.registerHelper("getProfileTimeStamp", function (column) {\n",
" return formatLabelDate(+column.properties.dataTimestamp)\n",
" });\n",
"\n",
" Handlebars.registerHelper("getProfileName", function (column) {\n",
" return column.properties.tags.name\n",
" });\n",
"\n",
"\n",
" Handlebars.registerHelper("alertLIst", function (column) {\n",
" let alertListItem = column.map((value) => {\n",
" if (value[1][0]) {\n",
" let alertListValue = value[1].map((cstr)=>{\n",
" return alertListElement(value[0],cstr[0],cstr[cstr.length - 1] === 0 || (failedConstraints++, false), value[3])\n",
" })\n",
" return alertListValue.join(' ')\n",
" } else {\n",
" return alertListElement('', value[0], value[2] === 0 || (failedConstraints++, false), value[3])\n",
" }\n",
" })\n",
" $(document).ready(() => {\n",
" $(".wl__feature-count--discrete").append(failedConstraints)\n",
" $(".wl__feature-count--non-discrete").append(column.length - failedConstraints)\n",
" $(".wl__feature-count--unknown").append(column.length)\n",
" })\n",
" return alertListItem.join(' ')\n",
" });\n",
"\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function initHandlebarsTemplate() {\n",
" // Replace this context with JSON from .py file\n",
" const context = [["count of legs lower than 10", 1, 0, {"metric": "counts", "n": 5, "null": 1, "nan": 1, "inf": 0}], ["null percentage of legs lower than 0.05", 0, 1, {"metric": "counts", "n": 5, "null": 1, "nan": 1, "inf": 0}], ["null values of legs lower than 1", 0, 1, {"metric": "counts", "n": 5, "null": 1, "nan": 1, "inf": 0}], ["legs has no missing values", 0, 1, {"metric": "counts", "n": 5, "null": 1, "nan": 1, "inf": 0}], ["animal has no missing values", 1, 0, {"metric": "counts", "n": 5, "null": 0, "nan": 0, "inf": 0}]];\n",
" // Config handlebars and pass data to HBS template\n",
" const source = document.getElementById("entry-template").innerHTML;\n",
" const template = Handlebars.compile(source);\n",
" const html = template(context);\n",
" const target = document.getElementById("generated-html");\n",
" target.innerHTML = html;\n",
" }\n",
"\n",
" function initWebsiteScripts() {\n",
" const $featureSearch = document.getElementById("wl__feature-search");\n",
" const $alertList = document.getElementById("alert-list");\n",
" const $discrete = document.getElementById("inferredDiscrete");\n",
" const $nonDiscrete = document.getElementById("inferredNonDiscrete");\n",
" const $unknown = document.getElementById("inferredUnknown");\n",
"\n",
" const activeTypes = {\n",
" passed: true,\n",
" failed: true\n",
" };\n",
"\n",
" let searchString = "";\n",
"\n",
" function debounce(func, wait, immediate) {\n",
" let timeout;\n",
"\n",
" return function () {\n",
" const context = this;\n",
" const args = arguments;\n",
" const later = function () {\n",
" timeout = null;\n",
" if (!immediate) func.apply(context, args);\n",
" };\n",
"\n",
" const callNow = immediate && !timeout;\n",
" clearTimeout(timeout);\n",
" timeout = setTimeout(later, wait);\n",
" if (callNow) func.apply(context, args);\n",
" };\n",
" }\n",
"\n",
" function filterNotification() {\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const $boxes = $('.wl_filter-options>.form-check>input[name=checkbox]:checked');\n",
" const item = Object.values($boxes).find(function(value) { return $(value)[0] === undefined});\n",
" if (item === undefined) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" } else {\n",
" $notifCircleContainer.addClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function handleSearch() {\n",
" const tableBodyChildren = $alertList.children;\n",
"\n",
" for (let i = 0; i < tableBodyChildren.length; i++) {\n",
" const type = tableBodyChildren[i].dataset.inferredType.toLowerCase();\n",
" const name = $(tableBodyChildren[i].children[0]).html().toLowerCase();\n",
" if (activeTypes[type] && name.includes(searchString)) {\n",
" tableBodyChildren[i].style.display = "";\n",
" } else {\n",
" tableBodyChildren[i].style.display = "none";\n",
" }\n",
" }\n",
" }\n",
"\n",
" const checkedBoxes = () => {\n",
" if ($('.form-check-input:checked').length === $(".form-check-input").length - 1) {\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", true );\n",
" }\n",
" }\n",
"\n",
" $featureSearch.addEventListener(\n",
" "keyup",\n",
" debounce((event) => {\n",
" searchString = event.target.value.toLowerCase();\n",
" handleSearch();\n",
" }, 100),\n",
" );\n",
"\n",
" $discrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["failed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $nonDiscrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["passed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["passed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $unknown.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" $(".form-check-input").prop( "checked", true );\n",
" activeTypes["passed"] = true;\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" $(".form-check-input").prop( "checked", false );\n",
" activeTypes["passed"] = false;\n",
" activeTypes["failed"] = false;\n",
" }\n",
" handleSearch();\n",
" });\n",
" }\n",
"\n",
" function checkedBoxes() {\n",
" const $boxes = $('input[name=checkbox]:checked');\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
"\n",
" if ($boxes.length) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $notifCircleContainer.addClass("d-none")\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" checkedBoxes()\n",
" }\n",
" }\n",
"\n",
" // Invoke functions -- keep in mind invokation order\n",
" registerHandlebarHelperFunctions();\n",
" initHandlebarsTemplate();\n",
" initWebsiteScripts();\n",
" </script>\n",
"</html>\n",
"\" width=100% height=300\n",
" frameBorder=0></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"builder = ConstraintsBuilder(dataset_profile_view=profile_view)\n",
"builder.add_constraint(count_below_number(column_name=\"legs\", number=10))\n",
"builder.add_constraint(null_percentage_below_number(column_name=\"legs\", number=0.05))\n",
"builder.add_constraint(null_values_below_number(column_name=\"legs\", number=1))\n",
"builder.add_constraint(no_missing_values(column_name=\"legs\"))\n",
"builder.add_constraint(no_missing_values(column_name=\"animal\"))\n",
"\n",
"constraints = builder.build()\n",
"\n",
"from whylogs.viz import NotebookProfileVisualizer\n",
"\n",
"visualization = NotebookProfileVisualizer()\n",
"visualization.constraints_report(constraints, cell_height=300)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Cardinality Constraints <a class=\"anchor\" id=\"card\"></a>"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"from whylogs.core.constraints.factories import distinct_number_in_range"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples - Cardinality Constraints"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"import whylogs as why\n",
"import pandas as pd\n",
"data = {\n",
" \"animal\": [\"cat\", \"snake\", \"snake\", \"cat\", \"mosquito\"],\n",
" \"legs\": [4, 2, 0, None, 6],\n",
" \"weight\": [4.3, 1.8, 1.3, 4.1, 5.5e-6],\n",
"}\n",
"\n",
"results = why.log(pd.DataFrame(data))\n",
"profile_view = results.view()"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div></div><iframe srcdoc=\"<!DOCTYPE html>\n",
"<html lang="en">\n",
" <head>\n",
" <meta charset="UTF-8" />\n",
" <meta http-equiv="X-UA-Compatible" content="IE=edge" />\n",
" <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n",
" <meta name="description" content="" />\n",
" <meta name="author" content="" />\n",
"\n",
" <title>Profile Visualizer | whylogs</title>\n",
"\n",
" <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />\n",
" <link rel="preconnect" href="https://fonts.googleapis.com" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n",
" <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" />\n",
" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />\n",
"\n",
" <script\n",
" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"\n",
" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="\n",
" crossorigin="anonymous"\n",
" referrerpolicy="no-referrer"\n",
" ></script>\n",
"\n",
" <style type="text/css">\n",
"\n",
" /* Screen on smaller screens */\n",
" .no-responsive {\n",
" display: none;\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1031;\n",
" width: 100vw;\n",
" height: 100vh;\n",
" background-color: var(--tealBackground);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" }\n",
"\n",
" @media screen and (min-width: 1000px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
"\n",
" .no-responsive__content {\n",
" max-width: 600px;\n",
" width: 100%;\n",
" padding: 0 24px;\n",
" }\n",
"\n",
" .no-responsive__title {\n",
" font-size: 96px;\n",
" font-weight: 300;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.167;\n",
" }\n",
"\n",
" .no-responsive__text {\n",
" margin: 0;\n",
" font-size: 16px;\n",
" font-weight: 400;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.5;\n",
" }\n",
"\n",
" .header-title {\n",
" font-size: 26px;\n",
" font-weight: 700;\n",
" color: #444444;\n",
" }\n",
"\n",
" .tooltip-full-number {\n",
" position: relative;\n",
" display: inline-block;\n",
" }\n",
"\n",
" .tooltip-full-number .tooltiptext {\n",
" visibility: hidden;\n",
" background: black;\n",
" color: white;\n",
" border: 1px solid black;\n",
" text-align: start;\n",
" padding: 3px;\n",
" position: absolute;\n",
" z-index: 1;\n",
" top: 0;\n",
" left: 100%;\n",
" margin-left: 5px;\n",
" opacity: 0;\n",
" transition: opacity 0.5s;\n",
" font-size: 13px;\n",
" font-weight: normal;\n",
" line-height: 100%;\n",
" }\n",
"\n",
" .tooltip-full-number:hover .tooltiptext {\n",
" visibility: visible;\n",
" opacity: 1;\n",
" }\n",
"\n",
"\n",
" .wl-compare-profile {\n",
" position: relative;\n",
" left: 0;\n",
" padding: 30px;\n",
" margin-bottom: 20px;\n",
" background: var(--white);;\n",
" border-bottom: 1px solid #CED4DA;\n",
" }\n",
"\n",
" .alert-list {\n",
" padding: 30px;\n",
" padding-top: 0;\n",
" }\n",
"\n",
" .drift-detection {\n",
" justify-content: space-between;\n",
" align-items: center;\n",
" }\n",
"\n",
" .drift-detection-info-circle {\n",
" width: 15px;\n",
" height: 15px;\n",
" border-radius: 50px;\n",
" display: inline-block;\n",
" margin-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item {\n",
" padding-right: 20px;\n",
" }\n",
"\n",
" .drift-detection-info-title {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 22px;\n",
" line-height: 130%;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-count {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 14px;\n",
" line-height: 16px;\n",
" color: #000000;\n",
" padding-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-name {\n",
" font-family: Arial;\n",
" font-style: normal;\n",
" font-weight: normal;\n",
" font-size: 12px;\n",
" line-height: 14px;\n",
" color: #000000;\n",
" }\n",
"\n",
" .drift-detection-search-input {\n",
" display: flex;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 170px;\n",
" padding-left: 10px;\n",
" }\n",
"\n",
" .drift-detection-search-input img{\n",
" margin-right: 5px;\n",
" }\n",
"\n",
" .drift-detection-search-input input::placeholder {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 13px;\n",
" line-height: 16px;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .dropdown-container {\n",
" position: absolute;\n",
" right: 30px;\n",
" top: 80px;\n",
" z-index: 999;\n",
" background: #FFFFFF;\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.05);\n",
" border-radius: 4px;\n",
" padding: 10px !important;\n",
" border: none !important;\n",
" }\n",
"\n",
" .filter-options-title {\n",
" width: 240px;\n",
" }\n",
"\n",
" .filter-options-title p {\n",
" margin: 0;\n",
" }\n",
"\n",
" .form-check-input:checked {\n",
" background-color: #0E7384;\n",
" border-color: #0E7384;\n",
" }\n",
"\n",
" .form-check-input[type=checkbox] {\n",
" border-radius: 2px;\n",
" }\n",
"\n",
" .search-input{\n",
" padding-top: 0 !important;\n",
" padding-bottom: 0 !important;\n",
" }\n",
"\n",
" .search-input input{\n",
" border: none;\n",
" background: none;\n",
" outline: none;\n",
" height: 40px;\n",
" width: 100%;\n",
" font-size: 14px;\n",
" }\n",
"\n",
" .search-input img{\n",
" height: 19px;\n",
" pointer-events: none;\n",
" }\n",
"\n",
" input::placeholder {\n",
" color: var(--secondaryLight1000);\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .close-filter-button {\n",
" display: flex;\n",
" justify-content: center;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #369BAC;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 40px;\n",
" height: 40px;\n",
" cursor: pointer;\n",
" margin-left: 10px;\n",
" }\n",
"\n",
" .statistic-number-title {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 20px;\n",
" color: #6C757D;\n",
" }\n",
"\n",
" .statistic-number {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 20px;\n",
" line-height: 140%;\n",
" display: flex;\n",
" align-items: center;\n",
" color: #4F595B;\n",
" }\n",
"\n",
" .full-summary-statistics-wrap {\n",
" padding: 20px;\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .statistics-list {\n",
" width: 100% ;\n",
" }\n",
"\n",
" mark {\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 140%;\n",
" }\n",
"\n",
" .blue-mark {\n",
" background-color: #369BAC1A;\n",
" color: #369BAC;\n",
" }\n",
"\n",
" .red-mark {\n",
" background-color: #FFEFEE;\n",
" color: #F5473C;\n",
" }\n",
"\n",
" .alert-tag {\n",
" height: 27px;\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 12px;\n",
" line-height: 140%;\n",
" color: #FFFFFF;\n",
" }\n",
"\n",
" .turquoise-background-color {\n",
" background-color: #1DBB42;\n",
" }\n",
"\n",
" .bordeaux-background-color {\n",
" background-color: #C6462A;\n",
" }\n",
"\n",
" .border-solid-gray {\n",
" border: 1px solid #CED4DA;\n",
" border-radius: 4px;\n",
" }\n",
"\n",
" .display-flex {\n",
" display: flex;\n",
" }\n",
"\n",
" .justify-content-space-between {\n",
" justify-content: space-between;\n",
" }\n",
"\n",
" .justify-content-center {\n",
" justify-content: center;\n",
" }\n",
"\n",
" .align-items-center {\n",
" align-items: center;\n",
" }\n",
"\n",
" .align-items-flex-start {\n",
" align-items: flex-start;\n",
" }\n",
"\n",
" .padding-right-30 {\n",
" padding-right: 30px;\n",
" }\n",
"\n",
" .notif-circle-container{\n",
" position: absolute;\n",
" top: 25px;\n",
" right: 25px;\n",
" padding: 5.3px;\n",
" border-radius: 50%;\n",
" background-color: white;\n",
" cursor: pointer;\n",
" }\n",
"\n",
" .notif-circle {\n",
" position: absolute;\n",
" top: 2px;\n",
" right: 2px;\n",
" padding: 3.3px;\n",
" border-radius: 50%;\n",
" background-color: #F2994A;\n",
" }\n",
"\n",
" .alert-list-text {\n",
" width: 70%\n",
" }\n",
"\n",
" @media screen and (min-width: 500px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
" </style>\n",
" </head>\n",
"\n",
" <body id="generated-html"></body>\n",
"\n",
" <script id="entry-template" type="text/x-handlebars-template">\n",
" \n",
" <div class="desktop-content">\n",
" <div class="full-summary-statistics-wrap">\n",
" <div class="full-summary-statistics">\n",
" <div>\n",
" <div class="display-flex justify-content-center">\n",
" <div class="statistics-list border-solid-gray">\n",
" <div>\n",
" <div class="wl-compare-profile" id="compare-profile">\n",
" <div class="drift-detection-wrap">\n",
" <div class="drift-detection display-flex align-items-flex-start">\n",
" <div class="drift-detection-info flex-direction-colum">\n",
" <div class="drift-detection-info-title-wrap display-flex">\n",
" <p class="drift-detection-info-title">\n",
" Constraints Report\n",
" </p>\n",
" </div>\n",
"\n",
" <!-- </div> -->\n",
" </div>\n",
" <div class="drift-detection-search-input-wrap display-flex">\n",
" <div class="drift-detection-search-input search-input">\n",
" <input type="text" id="wl__feature-search" placeholder="Quick search..."/>\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGdSURBVHgBpZK7TkJBEIZnZoVocdTYyQNALxpNKPQBMEaNJsbCRMKhl8ISWwt6AaksCF5iTHgAGhJD4AHkAaAzGiwUsjvOQnO4SYh/cXbPzO43OxcEj9Zy92EiFSXNIfvPyE1kKFfdoxJMENpP6DrvLC0vJoEwCgwto7DWcxoIIHBYbA3NmKwnDltjAeuZhyul1DaTTlfPB6Nt5Z53DOgky4P875+nlctY2+unjZviLklkJhi5bPUa3y/7qJuQUM7PinMy7CdQc1Gh16vnBxPzrMROmlKQEgKNASAHLQCmSIGpS75O+O5pdQAgVXaIqTkNwDDXHmcnW3VmHZoGMLoTsOt88+NrAMCIZdu+iLTyTwKRa1Md6YKfOgXbzO7K8sWku5u5RxcRV5EpPezrzcHGbXEXWaUkgkweZ/UC9YrK3zqggFw5FBZfm8EUavHj7AjAKpIvBDrGn+pNnlcyhYgqbcC41idr1gvB4SdZkDbzQa21gwv0Vj07aPTtL07XdDOyDXohCDNoHIRmAVRie20f+RKybRDQDvxHkXy/7b/DrayncLbMwQAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="wl__dropdown_arrow-icon">\n",
" <div onclick="openFilter()" class="close-filter-button">\n",
" <div class="display-flex close-filter-icon d-none">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADFSURBVHgBfY+xDcIwEEXvnLQBZQkYAEhDwwKpEEK0CCZgAEjJCEmgjYSAygxAHTZgFRSOsyUjY5mcZFnn/+78PwBXf3+MoKWUPuYjVBPFnTwpr9t/oNJfcTfXsAhRAlDqDhhQIPYgpAqNMDqcUqSAYZT1epr9gAHt6uXshvYme4DYHQJNDKh0dD0m5WXB10Y3Fqjtuh7fROn3oREDWxfeMLyRsMnc0OgDzdduaA0Pi3Plgr7Q2kaAePeBqh6rueSNBVt6fgCwBV1JLF3rlAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="display-flex filter-icon">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACSSURBVHgBrZLBCYAwDEWTUjw7igcdwI1cxkNXUJzBEVzFAbSVKoKmaVrEB6GHJv/w+AACtRk7P9IONv1QOYUl96k0zv61m2tjARoLtSDI3EFsgIJ4uoXrMLazO72CRG2mzg/8BSdVlEjhpGZJjAWdAZJECpWalEhJSs1pHuUlMad5FFai1Lwg4Ckx1TxKIPFL8w55mEWd8VjPGAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" </div>\n",
" <span class="notif-circle-container">\n",
" <span class="notif-circle"></span>\n",
" </span>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="dropdown-container flex-direction-colum mb-2 d-none" id="dropdown-container">\n",
" <div class="filter-options">\n",
" <div class="filter-options-title space-between dropdown">\n",
" <p>Select a view:</p>\n",
" </div>\n",
" <div class="form-check mb-1 mt-2">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Discrete"\n",
" id="inferredDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredDiscrete">\n",
" Failed constraints (<span class="wl__feature-count--discrete"></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Non-discrete"\n",
" id="inferredNonDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredNonDiscrete">\n",
" Passed constraints (<span\n",
" class="wl__feature-count--non-discrete"\n",
" ></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Unknown"\n",
" id="inferredUnknown"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredUnknown">\n",
" All constraints (<span class="wl__feature-count--unknown"></span>)\n",
" </label>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="alert-list" id="alert-list">\n",
" {{{alertLIst this}}}\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="no-responsive">\n",
" <div class="no-responsive__content">\n",
" <h1 class="no-responsive__title">Hold on! :)</h1>\n",
" <p class="no-responsive__text">\n",
" It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is\n",
" best experienced on a desktop computer. Please try maximizing this window or switching to another device. We\n",
" are working on adding support for a larger variety of devices.\n",
" </p>\n",
" </div>\n",
" </div>\n",
" \n",
" </script>\n",
"\n",
" <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>\n",
"\n",
" <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n",
"\n",
" <script>\n",
" function registerHandlebarHelperFunctions() {\n",
" //helper fun\n",
" function formatLabelDate(timestamp) {\n",
" const date = new Date(timestamp);\n",
" const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");\n",
" return format(date);\n",
" }\n",
"\n",
" function fixNumberTo(number, decimals = 3) {\n",
" return parseFloat(number).toFixed(decimals);\n",
" }\n",
"\n",
" const randomNumbers = (range) => Math.floor(Math.random() * range)\n",
"\n",
" const findFetureWithNumberSummary = (column) => {\n",
" const fetureIndex = Object.values(column.columns)\n",
" .findIndex((feture) => feture.numberSummary)\n",
"\n",
" return Object.keys(column.columns)[fetureIndex]\n",
" }\n",
"\n",
" const alertListItemStatus = (status, passedItem, failedItem) => {\n",
" if (status) {\n",
" return passedItem\n",
" } else {\n",
" return failedItem\n",
" }\n",
" }\n",
"\n",
" const alertListElement = (name, text, status, summary) => {\n",
" if (summary == null){\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="turquoise-background-color alert-tag">Passed</div>\n",
" `\n",
" ,\n",
" `\n",
" <div class="bordeaux-background-color alert-tag">Failed</div>\n",
" `\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
"\n",
" }\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="turquoise-background-color alert-tag">Passed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
"\n",
" ,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="bordeaux-background-color alert-tag">Failed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
" }\n",
"\n",
" let failedConstraints = 0;\n",
"\n",
" Handlebars.registerHelper("getProfileTimeStamp", function (column) {\n",
" return formatLabelDate(+column.properties.dataTimestamp)\n",
" });\n",
"\n",
" Handlebars.registerHelper("getProfileName", function (column) {\n",
" return column.properties.tags.name\n",
" });\n",
"\n",
"\n",
" Handlebars.registerHelper("alertLIst", function (column) {\n",
" let alertListItem = column.map((value) => {\n",
" if (value[1][0]) {\n",
" let alertListValue = value[1].map((cstr)=>{\n",
" return alertListElement(value[0],cstr[0],cstr[cstr.length - 1] === 0 || (failedConstraints++, false), value[3])\n",
" })\n",
" return alertListValue.join(' ')\n",
" } else {\n",
" return alertListElement('', value[0], value[2] === 0 || (failedConstraints++, false), value[3])\n",
" }\n",
" })\n",
" $(document).ready(() => {\n",
" $(".wl__feature-count--discrete").append(failedConstraints)\n",
" $(".wl__feature-count--non-discrete").append(column.length - failedConstraints)\n",
" $(".wl__feature-count--unknown").append(column.length)\n",
" })\n",
" return alertListItem.join(' ')\n",
" });\n",
"\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function initHandlebarsTemplate() {\n",
" // Replace this context with JSON from .py file\n",
" const context = [["animal distinct values estimate between 3 and 6 (inclusive)", 1, 0, {"metric": "cardinality", "est": 3.000000014901161, "upper_1": 3.0001498026537594, "lower_1": 3.0}]];\n",
" // Config handlebars and pass data to HBS template\n",
" const source = document.getElementById("entry-template").innerHTML;\n",
" const template = Handlebars.compile(source);\n",
" const html = template(context);\n",
" const target = document.getElementById("generated-html");\n",
" target.innerHTML = html;\n",
" }\n",
"\n",
" function initWebsiteScripts() {\n",
" const $featureSearch = document.getElementById("wl__feature-search");\n",
" const $alertList = document.getElementById("alert-list");\n",
" const $discrete = document.getElementById("inferredDiscrete");\n",
" const $nonDiscrete = document.getElementById("inferredNonDiscrete");\n",
" const $unknown = document.getElementById("inferredUnknown");\n",
"\n",
" const activeTypes = {\n",
" passed: true,\n",
" failed: true\n",
" };\n",
"\n",
" let searchString = "";\n",
"\n",
" function debounce(func, wait, immediate) {\n",
" let timeout;\n",
"\n",
" return function () {\n",
" const context = this;\n",
" const args = arguments;\n",
" const later = function () {\n",
" timeout = null;\n",
" if (!immediate) func.apply(context, args);\n",
" };\n",
"\n",
" const callNow = immediate && !timeout;\n",
" clearTimeout(timeout);\n",
" timeout = setTimeout(later, wait);\n",
" if (callNow) func.apply(context, args);\n",
" };\n",
" }\n",
"\n",
" function filterNotification() {\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const $boxes = $('.wl_filter-options>.form-check>input[name=checkbox]:checked');\n",
" const item = Object.values($boxes).find(function(value) { return $(value)[0] === undefined});\n",
" if (item === undefined) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" } else {\n",
" $notifCircleContainer.addClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function handleSearch() {\n",
" const tableBodyChildren = $alertList.children;\n",
"\n",
" for (let i = 0; i < tableBodyChildren.length; i++) {\n",
" const type = tableBodyChildren[i].dataset.inferredType.toLowerCase();\n",
" const name = $(tableBodyChildren[i].children[0]).html().toLowerCase();\n",
" if (activeTypes[type] && name.includes(searchString)) {\n",
" tableBodyChildren[i].style.display = "";\n",
" } else {\n",
" tableBodyChildren[i].style.display = "none";\n",
" }\n",
" }\n",
" }\n",
"\n",
" const checkedBoxes = () => {\n",
" if ($('.form-check-input:checked').length === $(".form-check-input").length - 1) {\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", true );\n",
" }\n",
" }\n",
"\n",
" $featureSearch.addEventListener(\n",
" "keyup",\n",
" debounce((event) => {\n",
" searchString = event.target.value.toLowerCase();\n",
" handleSearch();\n",
" }, 100),\n",
" );\n",
"\n",
" $discrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["failed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $nonDiscrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["passed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["passed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $unknown.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" $(".form-check-input").prop( "checked", true );\n",
" activeTypes["passed"] = true;\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" $(".form-check-input").prop( "checked", false );\n",
" activeTypes["passed"] = false;\n",
" activeTypes["failed"] = false;\n",
" }\n",
" handleSearch();\n",
" });\n",
" }\n",
"\n",
" function checkedBoxes() {\n",
" const $boxes = $('input[name=checkbox]:checked');\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
"\n",
" if ($boxes.length) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $notifCircleContainer.addClass("d-none")\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" checkedBoxes()\n",
" }\n",
" }\n",
"\n",
" // Invoke functions -- keep in mind invokation order\n",
" registerHandlebarHelperFunctions();\n",
" initHandlebarsTemplate();\n",
" initWebsiteScripts();\n",
" </script>\n",
"</html>\n",
"\" width=100% height=300\n",
" frameBorder=0></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"builder = ConstraintsBuilder(dataset_profile_view=profile_view)\n",
"builder.add_constraint(distinct_number_in_range(column_name = \"animal\", lower = 3, upper = 6))\n",
"\n",
"constraints = builder.build()\n",
"\n",
"from whylogs.viz import NotebookProfileVisualizer\n",
"\n",
"visualization = NotebookProfileVisualizer()\n",
"visualization.constraints_report(constraints, cell_height=300)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Types Metrics <a class=\"anchor\" id=\"types\"></a>"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples - Types Metrics"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"import whylogs as why\n",
"import pandas as pd\n",
"\n",
"data = {\n",
" \"animal\": [\"cat\", \"snake\", \"snake\", \"cat\", \"mosquito\"],\n",
" \"legs\": [4, 2, 0, None, 6],\n",
" \"weight\": [4.3, 1.8, 1.3, 4.1, 5.5e-6],\n",
" \"flies\": [False, False, \"False\", False, True],\n",
" \"obj\": [{\"a\":1}, None, {\"a\":1}, {\"a\":1}, {\"a\":1}]\n",
"}\n",
"df = pd.DataFrame(data)\n",
"results = why.log(df)\n",
"profile_view = results.view()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Check Nullable Types"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div></div><iframe srcdoc=\"<!DOCTYPE html>\n",
"<html lang="en">\n",
" <head>\n",
" <meta charset="UTF-8" />\n",
" <meta http-equiv="X-UA-Compatible" content="IE=edge" />\n",
" <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n",
" <meta name="description" content="" />\n",
" <meta name="author" content="" />\n",
"\n",
" <title>Profile Visualizer | whylogs</title>\n",
"\n",
" <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />\n",
" <link rel="preconnect" href="https://fonts.googleapis.com" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n",
" <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" />\n",
" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />\n",
"\n",
" <script\n",
" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"\n",
" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="\n",
" crossorigin="anonymous"\n",
" referrerpolicy="no-referrer"\n",
" ></script>\n",
"\n",
" <style type="text/css">\n",
"\n",
" /* Screen on smaller screens */\n",
" .no-responsive {\n",
" display: none;\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1031;\n",
" width: 100vw;\n",
" height: 100vh;\n",
" background-color: var(--tealBackground);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" }\n",
"\n",
" @media screen and (min-width: 1000px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
"\n",
" .no-responsive__content {\n",
" max-width: 600px;\n",
" width: 100%;\n",
" padding: 0 24px;\n",
" }\n",
"\n",
" .no-responsive__title {\n",
" font-size: 96px;\n",
" font-weight: 300;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.167;\n",
" }\n",
"\n",
" .no-responsive__text {\n",
" margin: 0;\n",
" font-size: 16px;\n",
" font-weight: 400;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.5;\n",
" }\n",
"\n",
" .header-title {\n",
" font-size: 26px;\n",
" font-weight: 700;\n",
" color: #444444;\n",
" }\n",
"\n",
" .tooltip-full-number {\n",
" position: relative;\n",
" display: inline-block;\n",
" }\n",
"\n",
" .tooltip-full-number .tooltiptext {\n",
" visibility: hidden;\n",
" background: black;\n",
" color: white;\n",
" border: 1px solid black;\n",
" text-align: start;\n",
" padding: 3px;\n",
" position: absolute;\n",
" z-index: 1;\n",
" top: 0;\n",
" left: 100%;\n",
" margin-left: 5px;\n",
" opacity: 0;\n",
" transition: opacity 0.5s;\n",
" font-size: 13px;\n",
" font-weight: normal;\n",
" line-height: 100%;\n",
" }\n",
"\n",
" .tooltip-full-number:hover .tooltiptext {\n",
" visibility: visible;\n",
" opacity: 1;\n",
" }\n",
"\n",
"\n",
" .wl-compare-profile {\n",
" position: relative;\n",
" left: 0;\n",
" padding: 30px;\n",
" margin-bottom: 20px;\n",
" background: var(--white);;\n",
" border-bottom: 1px solid #CED4DA;\n",
" }\n",
"\n",
" .alert-list {\n",
" padding: 30px;\n",
" padding-top: 0;\n",
" }\n",
"\n",
" .drift-detection {\n",
" justify-content: space-between;\n",
" align-items: center;\n",
" }\n",
"\n",
" .drift-detection-info-circle {\n",
" width: 15px;\n",
" height: 15px;\n",
" border-radius: 50px;\n",
" display: inline-block;\n",
" margin-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item {\n",
" padding-right: 20px;\n",
" }\n",
"\n",
" .drift-detection-info-title {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 22px;\n",
" line-height: 130%;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-count {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 14px;\n",
" line-height: 16px;\n",
" color: #000000;\n",
" padding-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-name {\n",
" font-family: Arial;\n",
" font-style: normal;\n",
" font-weight: normal;\n",
" font-size: 12px;\n",
" line-height: 14px;\n",
" color: #000000;\n",
" }\n",
"\n",
" .drift-detection-search-input {\n",
" display: flex;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 170px;\n",
" padding-left: 10px;\n",
" }\n",
"\n",
" .drift-detection-search-input img{\n",
" margin-right: 5px;\n",
" }\n",
"\n",
" .drift-detection-search-input input::placeholder {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 13px;\n",
" line-height: 16px;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .dropdown-container {\n",
" position: absolute;\n",
" right: 30px;\n",
" top: 80px;\n",
" z-index: 999;\n",
" background: #FFFFFF;\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.05);\n",
" border-radius: 4px;\n",
" padding: 10px !important;\n",
" border: none !important;\n",
" }\n",
"\n",
" .filter-options-title {\n",
" width: 240px;\n",
" }\n",
"\n",
" .filter-options-title p {\n",
" margin: 0;\n",
" }\n",
"\n",
" .form-check-input:checked {\n",
" background-color: #0E7384;\n",
" border-color: #0E7384;\n",
" }\n",
"\n",
" .form-check-input[type=checkbox] {\n",
" border-radius: 2px;\n",
" }\n",
"\n",
" .search-input{\n",
" padding-top: 0 !important;\n",
" padding-bottom: 0 !important;\n",
" }\n",
"\n",
" .search-input input{\n",
" border: none;\n",
" background: none;\n",
" outline: none;\n",
" height: 40px;\n",
" width: 100%;\n",
" font-size: 14px;\n",
" }\n",
"\n",
" .search-input img{\n",
" height: 19px;\n",
" pointer-events: none;\n",
" }\n",
"\n",
" input::placeholder {\n",
" color: var(--secondaryLight1000);\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .close-filter-button {\n",
" display: flex;\n",
" justify-content: center;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #369BAC;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 40px;\n",
" height: 40px;\n",
" cursor: pointer;\n",
" margin-left: 10px;\n",
" }\n",
"\n",
" .statistic-number-title {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 20px;\n",
" color: #6C757D;\n",
" }\n",
"\n",
" .statistic-number {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 20px;\n",
" line-height: 140%;\n",
" display: flex;\n",
" align-items: center;\n",
" color: #4F595B;\n",
" }\n",
"\n",
" .full-summary-statistics-wrap {\n",
" padding: 20px;\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .statistics-list {\n",
" width: 100% ;\n",
" }\n",
"\n",
" mark {\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 140%;\n",
" }\n",
"\n",
" .blue-mark {\n",
" background-color: #369BAC1A;\n",
" color: #369BAC;\n",
" }\n",
"\n",
" .red-mark {\n",
" background-color: #FFEFEE;\n",
" color: #F5473C;\n",
" }\n",
"\n",
" .alert-tag {\n",
" height: 27px;\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 12px;\n",
" line-height: 140%;\n",
" color: #FFFFFF;\n",
" }\n",
"\n",
" .turquoise-background-color {\n",
" background-color: #1DBB42;\n",
" }\n",
"\n",
" .bordeaux-background-color {\n",
" background-color: #C6462A;\n",
" }\n",
"\n",
" .border-solid-gray {\n",
" border: 1px solid #CED4DA;\n",
" border-radius: 4px;\n",
" }\n",
"\n",
" .display-flex {\n",
" display: flex;\n",
" }\n",
"\n",
" .justify-content-space-between {\n",
" justify-content: space-between;\n",
" }\n",
"\n",
" .justify-content-center {\n",
" justify-content: center;\n",
" }\n",
"\n",
" .align-items-center {\n",
" align-items: center;\n",
" }\n",
"\n",
" .align-items-flex-start {\n",
" align-items: flex-start;\n",
" }\n",
"\n",
" .padding-right-30 {\n",
" padding-right: 30px;\n",
" }\n",
"\n",
" .notif-circle-container{\n",
" position: absolute;\n",
" top: 25px;\n",
" right: 25px;\n",
" padding: 5.3px;\n",
" border-radius: 50%;\n",
" background-color: white;\n",
" cursor: pointer;\n",
" }\n",
"\n",
" .notif-circle {\n",
" position: absolute;\n",
" top: 2px;\n",
" right: 2px;\n",
" padding: 3.3px;\n",
" border-radius: 50%;\n",
" background-color: #F2994A;\n",
" }\n",
"\n",
" .alert-list-text {\n",
" width: 70%\n",
" }\n",
"\n",
" @media screen and (min-width: 500px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
" </style>\n",
" </head>\n",
"\n",
" <body id="generated-html"></body>\n",
"\n",
" <script id="entry-template" type="text/x-handlebars-template">\n",
" \n",
" <div class="desktop-content">\n",
" <div class="full-summary-statistics-wrap">\n",
" <div class="full-summary-statistics">\n",
" <div>\n",
" <div class="display-flex justify-content-center">\n",
" <div class="statistics-list border-solid-gray">\n",
" <div>\n",
" <div class="wl-compare-profile" id="compare-profile">\n",
" <div class="drift-detection-wrap">\n",
" <div class="drift-detection display-flex align-items-flex-start">\n",
" <div class="drift-detection-info flex-direction-colum">\n",
" <div class="drift-detection-info-title-wrap display-flex">\n",
" <p class="drift-detection-info-title">\n",
" Constraints Report\n",
" </p>\n",
" </div>\n",
"\n",
" <!-- </div> -->\n",
" </div>\n",
" <div class="drift-detection-search-input-wrap display-flex">\n",
" <div class="drift-detection-search-input search-input">\n",
" <input type="text" id="wl__feature-search" placeholder="Quick search..."/>\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGdSURBVHgBpZK7TkJBEIZnZoVocdTYyQNALxpNKPQBMEaNJsbCRMKhl8ISWwt6AaksCF5iTHgAGhJD4AHkAaAzGiwUsjvOQnO4SYh/cXbPzO43OxcEj9Zy92EiFSXNIfvPyE1kKFfdoxJMENpP6DrvLC0vJoEwCgwto7DWcxoIIHBYbA3NmKwnDltjAeuZhyul1DaTTlfPB6Nt5Z53DOgky4P875+nlctY2+unjZviLklkJhi5bPUa3y/7qJuQUM7PinMy7CdQc1Gh16vnBxPzrMROmlKQEgKNASAHLQCmSIGpS75O+O5pdQAgVXaIqTkNwDDXHmcnW3VmHZoGMLoTsOt88+NrAMCIZdu+iLTyTwKRa1Md6YKfOgXbzO7K8sWku5u5RxcRV5EpPezrzcHGbXEXWaUkgkweZ/UC9YrK3zqggFw5FBZfm8EUavHj7AjAKpIvBDrGn+pNnlcyhYgqbcC41idr1gvB4SdZkDbzQa21gwv0Vj07aPTtL07XdDOyDXohCDNoHIRmAVRie20f+RKybRDQDvxHkXy/7b/DrayncLbMwQAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="wl__dropdown_arrow-icon">\n",
" <div onclick="openFilter()" class="close-filter-button">\n",
" <div class="display-flex close-filter-icon d-none">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADFSURBVHgBfY+xDcIwEEXvnLQBZQkYAEhDwwKpEEK0CCZgAEjJCEmgjYSAygxAHTZgFRSOsyUjY5mcZFnn/+78PwBXf3+MoKWUPuYjVBPFnTwpr9t/oNJfcTfXsAhRAlDqDhhQIPYgpAqNMDqcUqSAYZT1epr9gAHt6uXshvYme4DYHQJNDKh0dD0m5WXB10Y3Fqjtuh7fROn3oREDWxfeMLyRsMnc0OgDzdduaA0Pi3Plgr7Q2kaAePeBqh6rueSNBVt6fgCwBV1JLF3rlAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="display-flex filter-icon">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACSSURBVHgBrZLBCYAwDEWTUjw7igcdwI1cxkNXUJzBEVzFAbSVKoKmaVrEB6GHJv/w+AACtRk7P9IONv1QOYUl96k0zv61m2tjARoLtSDI3EFsgIJ4uoXrMLazO72CRG2mzg/8BSdVlEjhpGZJjAWdAZJECpWalEhJSs1pHuUlMad5FFai1Lwg4Ckx1TxKIPFL8w55mEWd8VjPGAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" </div>\n",
" <span class="notif-circle-container">\n",
" <span class="notif-circle"></span>\n",
" </span>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="dropdown-container flex-direction-colum mb-2 d-none" id="dropdown-container">\n",
" <div class="filter-options">\n",
" <div class="filter-options-title space-between dropdown">\n",
" <p>Select a view:</p>\n",
" </div>\n",
" <div class="form-check mb-1 mt-2">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Discrete"\n",
" id="inferredDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredDiscrete">\n",
" Failed constraints (<span class="wl__feature-count--discrete"></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Non-discrete"\n",
" id="inferredNonDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredNonDiscrete">\n",
" Passed constraints (<span\n",
" class="wl__feature-count--non-discrete"\n",
" ></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Unknown"\n",
" id="inferredUnknown"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredUnknown">\n",
" All constraints (<span class="wl__feature-count--unknown"></span>)\n",
" </label>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="alert-list" id="alert-list">\n",
" {{{alertLIst this}}}\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="no-responsive">\n",
" <div class="no-responsive__content">\n",
" <h1 class="no-responsive__title">Hold on! :)</h1>\n",
" <p class="no-responsive__text">\n",
" It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is\n",
" best experienced on a desktop computer. Please try maximizing this window or switching to another device. We\n",
" are working on adding support for a larger variety of devices.\n",
" </p>\n",
" </div>\n",
" </div>\n",
" \n",
" </script>\n",
"\n",
" <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>\n",
"\n",
" <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n",
"\n",
" <script>\n",
" function registerHandlebarHelperFunctions() {\n",
" //helper fun\n",
" function formatLabelDate(timestamp) {\n",
" const date = new Date(timestamp);\n",
" const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");\n",
" return format(date);\n",
" }\n",
"\n",
" function fixNumberTo(number, decimals = 3) {\n",
" return parseFloat(number).toFixed(decimals);\n",
" }\n",
"\n",
" const randomNumbers = (range) => Math.floor(Math.random() * range)\n",
"\n",
" const findFetureWithNumberSummary = (column) => {\n",
" const fetureIndex = Object.values(column.columns)\n",
" .findIndex((feture) => feture.numberSummary)\n",
"\n",
" return Object.keys(column.columns)[fetureIndex]\n",
" }\n",
"\n",
" const alertListItemStatus = (status, passedItem, failedItem) => {\n",
" if (status) {\n",
" return passedItem\n",
" } else {\n",
" return failedItem\n",
" }\n",
" }\n",
"\n",
" const alertListElement = (name, text, status, summary) => {\n",
" if (summary == null){\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="turquoise-background-color alert-tag">Passed</div>\n",
" `\n",
" ,\n",
" `\n",
" <div class="bordeaux-background-color alert-tag">Failed</div>\n",
" `\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
"\n",
" }\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="turquoise-background-color alert-tag">Passed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
"\n",
" ,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="bordeaux-background-color alert-tag">Failed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
" }\n",
"\n",
" let failedConstraints = 0;\n",
"\n",
" Handlebars.registerHelper("getProfileTimeStamp", function (column) {\n",
" return formatLabelDate(+column.properties.dataTimestamp)\n",
" });\n",
"\n",
" Handlebars.registerHelper("getProfileName", function (column) {\n",
" return column.properties.tags.name\n",
" });\n",
"\n",
"\n",
" Handlebars.registerHelper("alertLIst", function (column) {\n",
" let alertListItem = column.map((value) => {\n",
" if (value[1][0]) {\n",
" let alertListValue = value[1].map((cstr)=>{\n",
" return alertListElement(value[0],cstr[0],cstr[cstr.length - 1] === 0 || (failedConstraints++, false), value[3])\n",
" })\n",
" return alertListValue.join(' ')\n",
" } else {\n",
" return alertListElement('', value[0], value[2] === 0 || (failedConstraints++, false), value[3])\n",
" }\n",
" })\n",
" $(document).ready(() => {\n",
" $(".wl__feature-count--discrete").append(failedConstraints)\n",
" $(".wl__feature-count--non-discrete").append(column.length - failedConstraints)\n",
" $(".wl__feature-count--unknown").append(column.length)\n",
" })\n",
" return alertListItem.join(' ')\n",
" });\n",
"\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function initHandlebarsTemplate() {\n",
" // Replace this context with JSON from .py file\n",
" const context = [["animal is nullable string", 1, 0, {"metric": "types", "integral": 0, "fractional": 0, "boolean": 0, "string": 5, "object": 0}], ["legs is nullable integral", 0, 1, {"metric": "types", "integral": 0, "fractional": 4, "boolean": 0, "string": 0, "object": 0}], ["weight is nullable fractional", 1, 0, {"metric": "types", "integral": 0, "fractional": 5, "boolean": 0, "string": 0, "object": 0}], ["flies is nullable boolean", 0, 1, {"metric": "types", "integral": 0, "fractional": 0, "boolean": 4, "string": 1, "object": 0}], ["obj is nullable object", 1, 0, {"metric": "types", "integral": 0, "fractional": 0, "boolean": 0, "string": 0, "object": 4}]];\n",
" // Config handlebars and pass data to HBS template\n",
" const source = document.getElementById("entry-template").innerHTML;\n",
" const template = Handlebars.compile(source);\n",
" const html = template(context);\n",
" const target = document.getElementById("generated-html");\n",
" target.innerHTML = html;\n",
" }\n",
"\n",
" function initWebsiteScripts() {\n",
" const $featureSearch = document.getElementById("wl__feature-search");\n",
" const $alertList = document.getElementById("alert-list");\n",
" const $discrete = document.getElementById("inferredDiscrete");\n",
" const $nonDiscrete = document.getElementById("inferredNonDiscrete");\n",
" const $unknown = document.getElementById("inferredUnknown");\n",
"\n",
" const activeTypes = {\n",
" passed: true,\n",
" failed: true\n",
" };\n",
"\n",
" let searchString = "";\n",
"\n",
" function debounce(func, wait, immediate) {\n",
" let timeout;\n",
"\n",
" return function () {\n",
" const context = this;\n",
" const args = arguments;\n",
" const later = function () {\n",
" timeout = null;\n",
" if (!immediate) func.apply(context, args);\n",
" };\n",
"\n",
" const callNow = immediate && !timeout;\n",
" clearTimeout(timeout);\n",
" timeout = setTimeout(later, wait);\n",
" if (callNow) func.apply(context, args);\n",
" };\n",
" }\n",
"\n",
" function filterNotification() {\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const $boxes = $('.wl_filter-options>.form-check>input[name=checkbox]:checked');\n",
" const item = Object.values($boxes).find(function(value) { return $(value)[0] === undefined});\n",
" if (item === undefined) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" } else {\n",
" $notifCircleContainer.addClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function handleSearch() {\n",
" const tableBodyChildren = $alertList.children;\n",
"\n",
" for (let i = 0; i < tableBodyChildren.length; i++) {\n",
" const type = tableBodyChildren[i].dataset.inferredType.toLowerCase();\n",
" const name = $(tableBodyChildren[i].children[0]).html().toLowerCase();\n",
" if (activeTypes[type] && name.includes(searchString)) {\n",
" tableBodyChildren[i].style.display = "";\n",
" } else {\n",
" tableBodyChildren[i].style.display = "none";\n",
" }\n",
" }\n",
" }\n",
"\n",
" const checkedBoxes = () => {\n",
" if ($('.form-check-input:checked').length === $(".form-check-input").length - 1) {\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", true );\n",
" }\n",
" }\n",
"\n",
" $featureSearch.addEventListener(\n",
" "keyup",\n",
" debounce((event) => {\n",
" searchString = event.target.value.toLowerCase();\n",
" handleSearch();\n",
" }, 100),\n",
" );\n",
"\n",
" $discrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["failed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $nonDiscrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["passed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["passed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $unknown.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" $(".form-check-input").prop( "checked", true );\n",
" activeTypes["passed"] = true;\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" $(".form-check-input").prop( "checked", false );\n",
" activeTypes["passed"] = false;\n",
" activeTypes["failed"] = false;\n",
" }\n",
" handleSearch();\n",
" });\n",
" }\n",
"\n",
" function checkedBoxes() {\n",
" const $boxes = $('input[name=checkbox]:checked');\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
"\n",
" if ($boxes.length) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $notifCircleContainer.addClass("d-none")\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" checkedBoxes()\n",
" }\n",
" }\n",
"\n",
" // Invoke functions -- keep in mind invokation order\n",
" registerHandlebarHelperFunctions();\n",
" initHandlebarsTemplate();\n",
" initWebsiteScripts();\n",
" </script>\n",
"</html>\n",
"\" width=100% height=300\n",
" frameBorder=0></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\n",
"from whylogs.core.constraints.factories import ( \n",
" column_is_nullable_integral,\n",
" column_is_nullable_boolean, \n",
" column_is_nullable_fractional,\n",
" column_is_nullable_object,\n",
" column_is_nullable_string,\n",
")\n",
"from whylogs.core.constraints import ConstraintsBuilder\n",
"\n",
"\n",
"builder = ConstraintsBuilder(dataset_profile_view=profile_view)\n",
"builder.add_constraint(column_is_nullable_string(column_name=\"animal\"))\n",
"builder.add_constraint(column_is_nullable_integral(column_name=\"legs\"))\n",
"builder.add_constraint(column_is_nullable_fractional(column_name=\"weight\"))\n",
"builder.add_constraint(column_is_nullable_boolean(column_name=\"flies\"))\n",
"builder.add_constraint(column_is_nullable_object(column_name=\"obj\"))\n",
"\n",
"constraints = builder.build()\n",
"\n",
"from whylogs.viz import NotebookProfileVisualizer\n",
"\n",
"visualization = NotebookProfileVisualizer()\n",
"visualization.constraints_report(constraints, cell_height=300)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"The constraints above will pass if all values are of a given type. Null values are accepted.\n",
"\n",
"Note that for `legs`, the constraints failed. That is because whylogs leverages __pandas' dtypes__ when it is available, and when a `None` is present, the column is considered to be `fractional`, even though the remaining values were originally integers. "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Combined Constraints <a class=\"anchor\" id=\"comb\"></a>"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Examples - Combined Metrics"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"To create a constraint that checks for a non-nullable type, we combine two separate constraints:\n",
"\n",
"- `column is nullable datatype`\n",
"- `null values below 1`"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"import whylogs as why\n",
"import pandas as pd\n",
"\n",
"data = {\n",
" \"animal\": [\"cat\", \"snake\", \"snake\", \"cat\", \"mosquito\"],\n",
" \"legs\": [4, 2, 0, None, 6],\n",
" \"weight\": [4.3, 1.8, 1.3, 4.1, 5.5e-6],\n",
" \"flies\": [False, False, \"False\", False, True],\n",
" \"obj\": [{\"a\":1}, None, {\"a\":1}, {\"a\":1}, {\"a\":1}]\n",
"}\n",
"df = pd.DataFrame(data)\n",
"results = why.log(df)\n",
"profile_view = results.view()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Check Non-nullable Types"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div></div><iframe srcdoc=\"<!DOCTYPE html>\n",
"<html lang="en">\n",
" <head>\n",
" <meta charset="UTF-8" />\n",
" <meta http-equiv="X-UA-Compatible" content="IE=edge" />\n",
" <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n",
" <meta name="description" content="" />\n",
" <meta name="author" content="" />\n",
"\n",
" <title>Profile Visualizer | whylogs</title>\n",
"\n",
" <link rel="icon" href="images/whylabs-favicon.png" type="image/png" sizes="16x16" />\n",
" <link rel="preconnect" href="https://fonts.googleapis.com" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n",
" <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet" />\n",
" <link rel="preconnect" href="https://fonts.gstatic.com" />\n",
" <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" />\n",
"\n",
" <script\n",
" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"\n",
" integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="\n",
" crossorigin="anonymous"\n",
" referrerpolicy="no-referrer"\n",
" ></script>\n",
"\n",
" <style type="text/css">\n",
"\n",
" /* Screen on smaller screens */\n",
" .no-responsive {\n",
" display: none;\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1031;\n",
" width: 100vw;\n",
" height: 100vh;\n",
" background-color: var(--tealBackground);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" }\n",
"\n",
" @media screen and (min-width: 1000px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
"\n",
" .no-responsive__content {\n",
" max-width: 600px;\n",
" width: 100%;\n",
" padding: 0 24px;\n",
" }\n",
"\n",
" .no-responsive__title {\n",
" font-size: 96px;\n",
" font-weight: 300;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.167;\n",
" }\n",
"\n",
" .no-responsive__text {\n",
" margin: 0;\n",
" font-size: 16px;\n",
" font-weight: 400;\n",
" color: var(--brandSecondary900);\n",
" line-height: 1.5;\n",
" }\n",
"\n",
" .header-title {\n",
" font-size: 26px;\n",
" font-weight: 700;\n",
" color: #444444;\n",
" }\n",
"\n",
" .tooltip-full-number {\n",
" position: relative;\n",
" display: inline-block;\n",
" }\n",
"\n",
" .tooltip-full-number .tooltiptext {\n",
" visibility: hidden;\n",
" background: black;\n",
" color: white;\n",
" border: 1px solid black;\n",
" text-align: start;\n",
" padding: 3px;\n",
" position: absolute;\n",
" z-index: 1;\n",
" top: 0;\n",
" left: 100%;\n",
" margin-left: 5px;\n",
" opacity: 0;\n",
" transition: opacity 0.5s;\n",
" font-size: 13px;\n",
" font-weight: normal;\n",
" line-height: 100%;\n",
" }\n",
"\n",
" .tooltip-full-number:hover .tooltiptext {\n",
" visibility: visible;\n",
" opacity: 1;\n",
" }\n",
"\n",
"\n",
" .wl-compare-profile {\n",
" position: relative;\n",
" left: 0;\n",
" padding: 30px;\n",
" margin-bottom: 20px;\n",
" background: var(--white);;\n",
" border-bottom: 1px solid #CED4DA;\n",
" }\n",
"\n",
" .alert-list {\n",
" padding: 30px;\n",
" padding-top: 0;\n",
" }\n",
"\n",
" .drift-detection {\n",
" justify-content: space-between;\n",
" align-items: center;\n",
" }\n",
"\n",
" .drift-detection-info-circle {\n",
" width: 15px;\n",
" height: 15px;\n",
" border-radius: 50px;\n",
" display: inline-block;\n",
" margin-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item {\n",
" padding-right: 20px;\n",
" }\n",
"\n",
" .drift-detection-info-title {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 22px;\n",
" line-height: 130%;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-count {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 14px;\n",
" line-height: 16px;\n",
" color: #000000;\n",
" padding-right: 8px;\n",
" }\n",
"\n",
" .drift-detection-info-drifts-item-name {\n",
" font-family: Arial;\n",
" font-style: normal;\n",
" font-weight: normal;\n",
" font-size: 12px;\n",
" line-height: 14px;\n",
" color: #000000;\n",
" }\n",
"\n",
" .drift-detection-search-input {\n",
" display: flex;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 170px;\n",
" padding-left: 10px;\n",
" }\n",
"\n",
" .drift-detection-search-input img{\n",
" margin-right: 5px;\n",
" }\n",
"\n",
" .drift-detection-search-input input::placeholder {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 13px;\n",
" line-height: 16px;\n",
" color: #313B3D;\n",
" }\n",
"\n",
" .dropdown-container {\n",
" position: absolute;\n",
" right: 30px;\n",
" top: 80px;\n",
" z-index: 999;\n",
" background: #FFFFFF;\n",
" border: 1px solid #DBE5E7;\n",
" box-sizing: border-box;\n",
" box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.05);\n",
" border-radius: 4px;\n",
" padding: 10px !important;\n",
" border: none !important;\n",
" }\n",
"\n",
" .filter-options-title {\n",
" width: 240px;\n",
" }\n",
"\n",
" .filter-options-title p {\n",
" margin: 0;\n",
" }\n",
"\n",
" .form-check-input:checked {\n",
" background-color: #0E7384;\n",
" border-color: #0E7384;\n",
" }\n",
"\n",
" .form-check-input[type=checkbox] {\n",
" border-radius: 2px;\n",
" }\n",
"\n",
" .search-input{\n",
" padding-top: 0 !important;\n",
" padding-bottom: 0 !important;\n",
" }\n",
"\n",
" .search-input input{\n",
" border: none;\n",
" background: none;\n",
" outline: none;\n",
" height: 40px;\n",
" width: 100%;\n",
" font-size: 14px;\n",
" }\n",
"\n",
" .search-input img{\n",
" height: 19px;\n",
" pointer-events: none;\n",
" }\n",
"\n",
" input::placeholder {\n",
" color: var(--secondaryLight1000);\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .close-filter-button {\n",
" display: flex;\n",
" justify-content: center;\n",
" align-items: center;\n",
" background: rgba(255, 255, 255, 0.7);\n",
" border: 1px solid #369BAC;\n",
" box-sizing: border-box;\n",
" border-radius: 4px;\n",
" width: 40px;\n",
" height: 40px;\n",
" cursor: pointer;\n",
" margin-left: 10px;\n",
" }\n",
"\n",
" .statistic-number-title {\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 20px;\n",
" color: #6C757D;\n",
" }\n",
"\n",
" .statistic-number {\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 20px;\n",
" line-height: 140%;\n",
" display: flex;\n",
" align-items: center;\n",
" color: #4F595B;\n",
" }\n",
"\n",
" .full-summary-statistics-wrap {\n",
" padding: 20px;\n",
" }\n",
"\n",
" .statistics {\n",
" width: 100%;\n",
" }\n",
"\n",
" .statistics-list {\n",
" width: 100% ;\n",
" }\n",
"\n",
" mark {\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: normal;\n",
" font-size: 14px;\n",
" line-height: 140%;\n",
" }\n",
"\n",
" .blue-mark {\n",
" background-color: #369BAC1A;\n",
" color: #369BAC;\n",
" }\n",
"\n",
" .red-mark {\n",
" background-color: #FFEFEE;\n",
" color: #F5473C;\n",
" }\n",
"\n",
" .alert-tag {\n",
" height: 27px;\n",
" padding: 5px;\n",
" border-radius: 4px;\n",
" font-family: Arial;\n",
" font-weight: bold;\n",
" font-size: 12px;\n",
" line-height: 140%;\n",
" color: #FFFFFF;\n",
" }\n",
"\n",
" .turquoise-background-color {\n",
" background-color: #1DBB42;\n",
" }\n",
"\n",
" .bordeaux-background-color {\n",
" background-color: #C6462A;\n",
" }\n",
"\n",
" .border-solid-gray {\n",
" border: 1px solid #CED4DA;\n",
" border-radius: 4px;\n",
" }\n",
"\n",
" .display-flex {\n",
" display: flex;\n",
" }\n",
"\n",
" .justify-content-space-between {\n",
" justify-content: space-between;\n",
" }\n",
"\n",
" .justify-content-center {\n",
" justify-content: center;\n",
" }\n",
"\n",
" .align-items-center {\n",
" align-items: center;\n",
" }\n",
"\n",
" .align-items-flex-start {\n",
" align-items: flex-start;\n",
" }\n",
"\n",
" .padding-right-30 {\n",
" padding-right: 30px;\n",
" }\n",
"\n",
" .notif-circle-container{\n",
" position: absolute;\n",
" top: 25px;\n",
" right: 25px;\n",
" padding: 5.3px;\n",
" border-radius: 50%;\n",
" background-color: white;\n",
" cursor: pointer;\n",
" }\n",
"\n",
" .notif-circle {\n",
" position: absolute;\n",
" top: 2px;\n",
" right: 2px;\n",
" padding: 3.3px;\n",
" border-radius: 50%;\n",
" background-color: #F2994A;\n",
" }\n",
"\n",
" .alert-list-text {\n",
" width: 70%\n",
" }\n",
"\n",
" @media screen and (min-width: 500px) {\n",
" .desktop-content {\n",
" display: block;\n",
" }\n",
" .no-responsive {\n",
" display: none;\n",
" }\n",
" }\n",
" </style>\n",
" </head>\n",
"\n",
" <body id="generated-html"></body>\n",
"\n",
" <script id="entry-template" type="text/x-handlebars-template">\n",
" \n",
" <div class="desktop-content">\n",
" <div class="full-summary-statistics-wrap">\n",
" <div class="full-summary-statistics">\n",
" <div>\n",
" <div class="display-flex justify-content-center">\n",
" <div class="statistics-list border-solid-gray">\n",
" <div>\n",
" <div class="wl-compare-profile" id="compare-profile">\n",
" <div class="drift-detection-wrap">\n",
" <div class="drift-detection display-flex align-items-flex-start">\n",
" <div class="drift-detection-info flex-direction-colum">\n",
" <div class="drift-detection-info-title-wrap display-flex">\n",
" <p class="drift-detection-info-title">\n",
" Constraints Report\n",
" </p>\n",
" </div>\n",
"\n",
" <!-- </div> -->\n",
" </div>\n",
" <div class="drift-detection-search-input-wrap display-flex">\n",
" <div class="drift-detection-search-input search-input">\n",
" <input type="text" id="wl__feature-search" placeholder="Quick search..."/>\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGdSURBVHgBpZK7TkJBEIZnZoVocdTYyQNALxpNKPQBMEaNJsbCRMKhl8ISWwt6AaksCF5iTHgAGhJD4AHkAaAzGiwUsjvOQnO4SYh/cXbPzO43OxcEj9Zy92EiFSXNIfvPyE1kKFfdoxJMENpP6DrvLC0vJoEwCgwto7DWcxoIIHBYbA3NmKwnDltjAeuZhyul1DaTTlfPB6Nt5Z53DOgky4P875+nlctY2+unjZviLklkJhi5bPUa3y/7qJuQUM7PinMy7CdQc1Gh16vnBxPzrMROmlKQEgKNASAHLQCmSIGpS75O+O5pdQAgVXaIqTkNwDDXHmcnW3VmHZoGMLoTsOt88+NrAMCIZdu+iLTyTwKRa1Md6YKfOgXbzO7K8sWku5u5RxcRV5EpPezrzcHGbXEXWaUkgkweZ/UC9YrK3zqggFw5FBZfm8EUavHj7AjAKpIvBDrGn+pNnlcyhYgqbcC41idr1gvB4SdZkDbzQa21gwv0Vj07aPTtL07XdDOyDXohCDNoHIRmAVRie20f+RKybRDQDvxHkXy/7b/DrayncLbMwQAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="wl__dropdown_arrow-icon">\n",
" <div onclick="openFilter()" class="close-filter-button">\n",
" <div class="display-flex close-filter-icon d-none">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADFSURBVHgBfY+xDcIwEEXvnLQBZQkYAEhDwwKpEEK0CCZgAEjJCEmgjYSAygxAHTZgFRSOsyUjY5mcZFnn/+78PwBXf3+MoKWUPuYjVBPFnTwpr9t/oNJfcTfXsAhRAlDqDhhQIPYgpAqNMDqcUqSAYZT1epr9gAHt6uXshvYme4DYHQJNDKh0dD0m5WXB10Y3Fqjtuh7fROn3oREDWxfeMLyRsMnc0OgDzdduaA0Pi3Plgr7Q2kaAePeBqh6rueSNBVt6fgCwBV1JLF3rlAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" <div class="display-flex filter-icon">\n",
" <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACSSURBVHgBrZLBCYAwDEWTUjw7igcdwI1cxkNXUJzBEVzFAbSVKoKmaVrEB6GHJv/w+AACtRk7P9IONv1QOYUl96k0zv61m2tjARoLtSDI3EFsgIJ4uoXrMLazO72CRG2mzg/8BSdVlEjhpGZJjAWdAZJECpWalEhJSs1pHuUlMad5FFai1Lwg4Ckx1TxKIPFL8w55mEWd8VjPGAAAAABJRU5ErkJggg=="/>\n",
" </div>\n",
" </div>\n",
" <span class="notif-circle-container">\n",
" <span class="notif-circle"></span>\n",
" </span>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="dropdown-container flex-direction-colum mb-2 d-none" id="dropdown-container">\n",
" <div class="filter-options">\n",
" <div class="filter-options-title space-between dropdown">\n",
" <p>Select a view:</p>\n",
" </div>\n",
" <div class="form-check mb-1 mt-2">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Discrete"\n",
" id="inferredDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredDiscrete">\n",
" Failed constraints (<span class="wl__feature-count--discrete"></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Non-discrete"\n",
" id="inferredNonDiscrete"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredNonDiscrete">\n",
" Passed constraints (<span\n",
" class="wl__feature-count--non-discrete"\n",
" ></span>)\n",
" </label>\n",
" </div>\n",
" <div class="form-check mb-1">\n",
" <input\n",
" class="form-check-input wl__feature-filter-input"\n",
" type="checkbox"\n",
" name="checkbox"\n",
" value="Unknown"\n",
" id="inferredUnknown"\n",
" checked\n",
" />\n",
" <label class="form-check-label" for="inferredUnknown">\n",
" All constraints (<span class="wl__feature-count--unknown"></span>)\n",
" </label>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="alert-list" id="alert-list">\n",
" {{{alertLIst this}}}\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" </div>\n",
" <div class="no-responsive">\n",
" <div class="no-responsive__content">\n",
" <h1 class="no-responsive__title">Hold on! :)</h1>\n",
" <p class="no-responsive__text">\n",
" It looks like your current screen size or device is not yet supported by the WhyLabs Sandbox. The Sandbox is\n",
" best experienced on a desktop computer. Please try maximizing this window or switching to another device. We\n",
" are working on adding support for a larger variety of devices.\n",
" </p>\n",
" </div>\n",
" </div>\n",
" \n",
" </script>\n",
"\n",
" <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>\n",
"\n",
" <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.7.0/d3.min.js" integrity="sha512-cd6CHE+XWDQ33ElJqsi0MdNte3S+bQY819f7p3NUHgwQQLXSKjE4cPZTeGNI+vaxZynk1wVU3hoHmow3m089wA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>\n",
"\n",
" <script>\n",
" function registerHandlebarHelperFunctions() {\n",
" //helper fun\n",
" function formatLabelDate(timestamp) {\n",
" const date = new Date(timestamp);\n",
" const format = d3.timeFormat("%Y-%m-%d %I:%M:%S %p %Z");\n",
" return format(date);\n",
" }\n",
"\n",
" function fixNumberTo(number, decimals = 3) {\n",
" return parseFloat(number).toFixed(decimals);\n",
" }\n",
"\n",
" const randomNumbers = (range) => Math.floor(Math.random() * range)\n",
"\n",
" const findFetureWithNumberSummary = (column) => {\n",
" const fetureIndex = Object.values(column.columns)\n",
" .findIndex((feture) => feture.numberSummary)\n",
"\n",
" return Object.keys(column.columns)[fetureIndex]\n",
" }\n",
"\n",
" const alertListItemStatus = (status, passedItem, failedItem) => {\n",
" if (status) {\n",
" return passedItem\n",
" } else {\n",
" return failedItem\n",
" }\n",
" }\n",
"\n",
" const alertListElement = (name, text, status, summary) => {\n",
" if (summary == null){\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="turquoise-background-color alert-tag">Passed</div>\n",
" `\n",
" ,\n",
" `\n",
" <div class="bordeaux-background-color alert-tag">Failed</div>\n",
" `\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
"\n",
" }\n",
" return (\n",
" `<div\n",
" data-inferred-type=${alertListItemStatus(status, "passed", "failed")}\n",
" class="alert-list-item display-flex justify-content-space-between align-items-center mb-2"\n",
" >\n",
" <div class="alert-list-text">\n",
" ${\n",
" name &&\n",
" alertListItemStatus(\n",
" status,\n",
" `<mark class="blue-mark">${name}</mark>`,\n",
" `<mark class="red-mark">${name}</mark>`\n",
" )\n",
" }\n",
" ${text}\n",
" </div>\n",
" ${\n",
" alertListItemStatus(\n",
" status,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="turquoise-background-color alert-tag">Passed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
"\n",
" ,\n",
" `\n",
" <div class="tooltip-full-number">\n",
" <div class="bordeaux-background-color alert-tag">Failed\n",
" <span class="tooltiptext">\n",
" <pre class="mb-1"> ${JSON.stringify(summary, null, 2)} </pre>\n",
" </span>\n",
" </div>\n",
" </div>`\n",
" )\n",
" }\n",
" </div>`\n",
" )\n",
" }\n",
"\n",
" let failedConstraints = 0;\n",
"\n",
" Handlebars.registerHelper("getProfileTimeStamp", function (column) {\n",
" return formatLabelDate(+column.properties.dataTimestamp)\n",
" });\n",
"\n",
" Handlebars.registerHelper("getProfileName", function (column) {\n",
" return column.properties.tags.name\n",
" });\n",
"\n",
"\n",
" Handlebars.registerHelper("alertLIst", function (column) {\n",
" let alertListItem = column.map((value) => {\n",
" if (value[1][0]) {\n",
" let alertListValue = value[1].map((cstr)=>{\n",
" return alertListElement(value[0],cstr[0],cstr[cstr.length - 1] === 0 || (failedConstraints++, false), value[3])\n",
" })\n",
" return alertListValue.join(' ')\n",
" } else {\n",
" return alertListElement('', value[0], value[2] === 0 || (failedConstraints++, false), value[3])\n",
" }\n",
" })\n",
" $(document).ready(() => {\n",
" $(".wl__feature-count--discrete").append(failedConstraints)\n",
" $(".wl__feature-count--non-discrete").append(column.length - failedConstraints)\n",
" $(".wl__feature-count--unknown").append(column.length)\n",
" })\n",
" return alertListItem.join(' ')\n",
" });\n",
"\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function initHandlebarsTemplate() {\n",
" // Replace this context with JSON from .py file\n",
" const context = [["animal is nullable string", 1, 0, {"metric": "types", "integral": 0, "fractional": 0, "boolean": 0, "string": 5, "object": 0}], ["null values of animal lower than 1", 1, 0, {"metric": "counts", "n": 5, "null": 0, "nan": 0, "inf": 0}], ["legs is nullable integral", 0, 1, {"metric": "types", "integral": 0, "fractional": 4, "boolean": 0, "string": 0, "object": 0}], ["null values of legs lower than 1", 0, 1, {"metric": "counts", "n": 5, "null": 1, "nan": 1, "inf": 0}], ["weight is nullable fractional", 1, 0, {"metric": "types", "integral": 0, "fractional": 5, "boolean": 0, "string": 0, "object": 0}], ["null values of weight lower than 1", 1, 0, {"metric": "counts", "n": 5, "null": 0, "nan": 0, "inf": 0}], ["flies is nullable boolean", 0, 1, {"metric": "types", "integral": 0, "fractional": 0, "boolean": 4, "string": 1, "object": 0}], ["null values of flies lower than 1", 1, 0, {"metric": "counts", "n": 5, "null": 0, "nan": 0, "inf": 0}], ["obj is nullable object", 1, 0, {"metric": "types", "integral": 0, "fractional": 0, "boolean": 0, "string": 0, "object": 4}], ["null values of obj lower than 1", 0, 1, {"metric": "counts", "n": 5, "null": 1, "nan": 0, "inf": 0}]];\n",
" // Config handlebars and pass data to HBS template\n",
" const source = document.getElementById("entry-template").innerHTML;\n",
" const template = Handlebars.compile(source);\n",
" const html = template(context);\n",
" const target = document.getElementById("generated-html");\n",
" target.innerHTML = html;\n",
" }\n",
"\n",
" function initWebsiteScripts() {\n",
" const $featureSearch = document.getElementById("wl__feature-search");\n",
" const $alertList = document.getElementById("alert-list");\n",
" const $discrete = document.getElementById("inferredDiscrete");\n",
" const $nonDiscrete = document.getElementById("inferredNonDiscrete");\n",
" const $unknown = document.getElementById("inferredUnknown");\n",
"\n",
" const activeTypes = {\n",
" passed: true,\n",
" failed: true\n",
" };\n",
"\n",
" let searchString = "";\n",
"\n",
" function debounce(func, wait, immediate) {\n",
" let timeout;\n",
"\n",
" return function () {\n",
" const context = this;\n",
" const args = arguments;\n",
" const later = function () {\n",
" timeout = null;\n",
" if (!immediate) func.apply(context, args);\n",
" };\n",
"\n",
" const callNow = immediate && !timeout;\n",
" clearTimeout(timeout);\n",
" timeout = setTimeout(later, wait);\n",
" if (callNow) func.apply(context, args);\n",
" };\n",
" }\n",
"\n",
" function filterNotification() {\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const $boxes = $('.wl_filter-options>.form-check>input[name=checkbox]:checked');\n",
" const item = Object.values($boxes).find(function(value) { return $(value)[0] === undefined});\n",
" if (item === undefined) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" } else {\n",
" $notifCircleContainer.addClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function handleSearch() {\n",
" const tableBodyChildren = $alertList.children;\n",
"\n",
" for (let i = 0; i < tableBodyChildren.length; i++) {\n",
" const type = tableBodyChildren[i].dataset.inferredType.toLowerCase();\n",
" const name = $(tableBodyChildren[i].children[0]).html().toLowerCase();\n",
" if (activeTypes[type] && name.includes(searchString)) {\n",
" tableBodyChildren[i].style.display = "";\n",
" } else {\n",
" tableBodyChildren[i].style.display = "none";\n",
" }\n",
" }\n",
" }\n",
"\n",
" const checkedBoxes = () => {\n",
" if ($('.form-check-input:checked').length === $(".form-check-input").length - 1) {\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", true );\n",
" }\n",
" }\n",
"\n",
" $featureSearch.addEventListener(\n",
" "keyup",\n",
" debounce((event) => {\n",
" searchString = event.target.value.toLowerCase();\n",
" handleSearch();\n",
" }, 100),\n",
" );\n",
"\n",
" $discrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["failed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $nonDiscrete.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" activeTypes["passed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" activeTypes["passed"] = false;\n",
" $($(".form-check-input")[$(".form-check-input").length - 1]).prop( "checked", false );\n",
" }\n",
" handleSearch();\n",
" });\n",
"\n",
" $unknown.addEventListener("change", (event) => {\n",
" const currentCheckbox = $(event.currentTarget);\n",
"\n",
" if (event.currentTarget.checked) {\n",
" $(".form-check-input").prop( "checked", true );\n",
" activeTypes["passed"] = true;\n",
" activeTypes["failed"] = true;\n",
" checkedBoxes();\n",
" } else {\n",
" $(".form-check-input").prop( "checked", false );\n",
" activeTypes["passed"] = false;\n",
" activeTypes["failed"] = false;\n",
" }\n",
" handleSearch();\n",
" });\n",
" }\n",
"\n",
" function checkedBoxes() {\n",
" const $boxes = $('input[name=checkbox]:checked');\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
"\n",
" if ($boxes.length) {\n",
" $notifCircleContainer.removeClass("d-none")\n",
" }\n",
" }\n",
"\n",
" function openFilter() {\n",
" const $filterOptions = $(".dropdown-container");\n",
" const $notifCircleContainer = $(".notif-circle-container")\n",
" const filterClass = $filterOptions.attr("class");\n",
"\n",
" if (filterClass.indexOf("d-none") > 0) {\n",
" $notifCircleContainer.addClass("d-none")\n",
" $filterOptions.removeClass("d-none");\n",
" $(".filter-icon").addClass("d-none")\n",
" $(".close-filter-icon").removeClass("d-none")\n",
" } else {\n",
" $filterOptions.addClass("d-none");\n",
" $(".close-filter-icon").addClass("d-none")\n",
" $(".filter-icon").removeClass("d-none")\n",
" checkedBoxes()\n",
" }\n",
" }\n",
"\n",
" // Invoke functions -- keep in mind invokation order\n",
" registerHandlebarHelperFunctions();\n",
" initHandlebarsTemplate();\n",
" initWebsiteScripts();\n",
" </script>\n",
"</html>\n",
"\" width=100% height=300\n",
" frameBorder=0></iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from whylogs.core.constraints.factories import ( \n",
" column_is_nullable_integral,\n",
" column_is_nullable_boolean, \n",
" column_is_nullable_fractional,\n",
" column_is_nullable_object,\n",
" column_is_nullable_string,\n",
" null_values_below_number,\n",
")\n",
"from whylogs.core.constraints import ConstraintsBuilder\n",
"\n",
"\n",
"builder = ConstraintsBuilder(dataset_profile_view=profile_view)\n",
"builder.add_constraint(column_is_nullable_string(column_name=\"animal\"))\n",
"builder.add_constraint(null_values_below_number(column_name=\"animal\",number=1))\n",
"\n",
"# The combination of these metrics makes a check of non-nullable integral\n",
"builder.add_constraint(column_is_nullable_integral(column_name=\"legs\"))\n",
"builder.add_constraint(null_values_below_number(column_name=\"legs\",number=1))\n",
"\n",
"# The combination of these metrics makes a check of non-nullable fractional\n",
"builder.add_constraint(column_is_nullable_fractional(column_name=\"weight\"))\n",
"builder.add_constraint(null_values_below_number(column_name=\"weight\",number=1))\n",
"\n",
"# The combination of these metrics makes a check of non-nullable boolean\n",
"builder.add_constraint(column_is_nullable_boolean(column_name=\"flies\"))\n",
"builder.add_constraint(null_values_below_number(column_name=\"flies\",number=1))\n",
"\n",
"# The combination of these metrics makes a check of non-nullable object\n",
"builder.add_constraint(column_is_nullable_object(column_name=\"obj\"))\n",
"builder.add_constraint(null_values_below_number(column_name=\"obj\",number=1))\n",
"\n",
"constraints = builder.build()\n",
"\n",
"from whylogs.viz import NotebookProfileVisualizer\n",
"\n",
"visualization = NotebookProfileVisualizer()\n",
"visualization.constraints_report(constraints, cell_height=300)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.8.10 ('.venv': poetry)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "5dd5901cadfd4b29c2aaf95ecd29c0c3b10829ad94dcfe59437dbee391154aea"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}