We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] Calling `save_as_html` can raise an error if the label column is imbalanced and has the type `np.bool_`
**Describe the bug**
The error comes from this chart (section "Train Test Label Drift"):
![image](https://user-images.githubusercontent.com/17814966/152127072-57de57d7-1030-42e4-b03c-6a2d5e4305ae.png)

This bar chart is created whenever the label is imbalanced and drifts between train and test (which is the case with my data).

The x axis has the values `False` and `True` with the dtype `np.bool_`. Before saving as HTML, somewhere in the code, this diagram is encoded as JSON. The call to `json.dumps` causes the error. The solution is to convert the problematic data to the regular Python `bool` type.

**To Reproduce**
Steps to reproduce the behavior:
1. Run the code below
2. See error: "TypeError: Object of type bool_ is not JSON serializable"

```python
import pandas as pd
import numpy as np

from deepchecks import Dataset
from deepchecks.suites import train_test_validation


if __name__ == "__main__":
    # Generate some random data
    # Note that the data type of the generated label is numpy.bool_
    # (in my project, the label column has this type)
    np.random.seed(42)
    training_size = 1000
    training_positive_proportion = 0.01  # Very low proportion to simulate an imbalanced dataset
    testing_size = 100
    testing_positive_proportion = 0.05  # This proportion is different from training to simulate a drift on the label
    training_df = pd.DataFrame({
        "feature_1": np.ones(training_size),
        "label": np.random.choice(a=[False, True], size=(training_size,), p=[training_positive_proportion, 1 - training_positive_proportion])
    })
    testing_df = pd.DataFrame({
        "feature_1": np.ones(testing_size),
        "label": np.random.choice(a=[False, True], size=(testing_size,), p=[testing_positive_proportion, 1 - testing_positive_proportion])
    })

    # Run the train_test_validation suite
    training_ds = Dataset(df=training_df, label="label", features=["feature_1"])
    testing_ds = Dataset(df=testing_df, label="label", features=["feature_1"])
    suite = train_test_validation()
    results = suite.run(train_dataset=training_ds, test_dataset=testing_ds)

    # Save as HTML, this will raise the following error:
    # "TypeError: Object of type bool_ is not JSON serializable"
    results.save_as_html("output.html")
```

**Expected behavior**
I would expect deepchecks to deal with this internally by converting the legend values to `bool`.

**Environment (please complete the following information):**
 - OS: Ubuntu 20.04 (running on Windows 10 with WSL)
 - Python Version: 3.8.10
 - Deepchecks Version: 0.4.1

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `deepchecks/utils/distribution/plot.py`
Content:
```
1 # ----------------------------------------------------------------------------
2 # Copyright (C) 2021-2022 Deepchecks (https://www.deepchecks.com)
3 #
4 # This file is part of Deepchecks.
5 # Deepchecks is distributed under the terms of the GNU Affero General
6 # Public License (version 3 or later).
7 # You should have received a copy of the GNU Affero General Public License
8 # along with Deepchecks.  If not, see <http://www.gnu.org/licenses/>.
9 # ----------------------------------------------------------------------------
10 #
11 """A module containing utils for plotting distributions."""
12 import numpy as np
13 import pandas as pd
14 from scipy.stats import gaussian_kde
15 import plotly.graph_objs as go
16 
17 __all__ = ['feature_distribution_traces', 'drift_score_bar_traces', 'get_density']
18 
19 from typing import List, Union, Dict, Tuple
20 
21 from deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins
22 from deepchecks.utils.plot import colors
23 
24 
25 def get_density(data, xs) -> np.ndarray:
26     """Get gaussian kde density to plot.
27 
28     Parameters
29     ----------
30     data
31         The data used to compute the pdf function.
32     xs : iterable
33         List of x values to plot the computed pdf for.
34     Returns
35     -------
36     np.array
37         The computed pdf values at the points xs.
38     """
39     # Is only single value adds noise, otherwise there is singular matrix error
40     if len(np.unique(data)) == 1:
41         data = data + np.random.normal(scale=10 * np.finfo(np.float32).eps, size=len(data))
42     density = gaussian_kde(data)
43     density.covariance_factor = lambda: .25
44     # pylint: disable=protected-access
45     density._compute_covariance()
46     return density(xs)
47 
48 
49 def drift_score_bar_traces(drift_score: float, bar_max: float = None) -> Tuple[List[go.Bar], Dict, Dict]:
50     """Create a traffic light bar traces for drift score.
51 
52     Parameters
53     ----------
54     drift_score : float
55         Drift score
56     bar_max : float , default: None
57         Maximum value for the bar
58     Returns
59     -------
60     Tuple[List[go.Bar], Dict, Dict]
61         list of plotly bar traces.
62     """
63     traffic_light_colors = [((0, 0.1), '#01B8AA'),
64                             ((0.1, 0.2), '#F2C80F'),
65                             ((0.2, 0.3), '#FE9666'),
66                             ((0.3, 1), '#FD625E')
67                             ]
68 
69     bars = []
70 
71     for range_tuple, color in traffic_light_colors:
72         if drift_score < range_tuple[0]:
73             break
74 
75         bars.append(go.Bar(
76             x=[min(drift_score, range_tuple[1]) - range_tuple[0]],
77             y=['Drift Score'],
78             orientation='h',
79             marker=dict(
80                 color=color,
81             ),
82             offsetgroup=0,
83             base=range_tuple[0],
84             showlegend=False
85 
86         ))
87 
88     bar_stop = max(0.4, drift_score + 0.1)
89     if bar_max:
90         bar_stop = min(bar_stop, bar_max)
91     xaxis = dict(
92         showgrid=False,
93         gridcolor='black',
94         linecolor='black',
95         range=[0, bar_stop],
96         dtick=0.05,
97         fixedrange=True
98     )
99     yaxis = dict(
100         showgrid=False,
101         showline=False,
102         showticklabels=False,
103         zeroline=False,
104         color='black',
105         fixedrange=True
106     )
107 
108     return bars, xaxis, yaxis
109 
110 
111 def feature_distribution_traces(train_column,
112                                 test_column,
113                                 is_categorical: bool = False,
114                                 max_num_categories: int = 10,
115                                 quantile_cut: float = 0.02) -> Tuple[List[Union[go.Bar, go.Scatter]], Dict, Dict]:
116     """Create traces for comparison between train and test column.
117 
118     Parameters
119     ----------
120     train_column
121         Train data used to trace distribution.
122     test_column
123         Test data used to trace distribution.
124     is_categorical : bool , default: False
125         State if column is categorical.
126     max_num_categories : int , default: 10
127         Maximum number of categories to show in plot (default: 10).
128     quantile_cut : float , default: 0.02
129         in which quantile to cut the edges of the plot
130     Returns
131     -------
132     List[Union[go.Bar, go.Scatter]]
133         list of plotly traces.
134     Dict
135         layout of x axis
136     Dict
137         layout of y axis
138     """
139     if is_categorical:
140         expected_percents, actual_percents, categories_list = \
141             preprocess_2_cat_cols_to_same_bins(dist1=train_column, dist2=test_column,
142                                                max_num_categories=max_num_categories)
143         cat_df = pd.DataFrame({'Train dataset': expected_percents, 'Test dataset': actual_percents},
144                               index=categories_list)
145         train_bar = go.Bar(
146             x=cat_df.index,
147             y=cat_df['Train dataset'],
148             marker=dict(
149                 color=colors['Train'],
150             ),
151             name='Train Dataset',
152         )
153 
154         test_bar = go.Bar(
155             x=cat_df.index,
156             y=cat_df['Test dataset'],
157             marker=dict(
158                 color=colors['Test'],
159             ),
160             name='Test Dataset',
161         )
162 
163         traces = [train_bar, test_bar]
164 
165         xaxis_layout = dict(type='category')
166         yaxis_layout = dict(fixedrange=True,
167                             range=(0, 1),
168                             title='Percentage')
169 
170     else:
171         x_range = (min(train_column.min(), test_column.min()), max(train_column.max(), test_column.max()))
172         x_range_to_show = (
173             min(np.quantile(train_column, quantile_cut), np.quantile(test_column, quantile_cut)),
174             max(np.quantile(train_column, 1 - quantile_cut), np.quantile(test_column, 1 - quantile_cut))
175         )
176         # Heuristically take points on x-axis to show on the plot
177         # The intuition is the graph will look "smooth" wherever we will zoom it
178         xs = sorted(np.concatenate((
179             np.linspace(x_range[0], x_range[1], 50),
180             np.quantile(train_column, q=np.arange(0.02, 1, 0.02)),
181             np.quantile(test_column, q=np.arange(0.02, 1, 0.02))
182         )))
183 
184         traces = [go.Scatter(x=xs, y=get_density(train_column, xs), fill='tozeroy', name='Train Dataset',
185                              line_color=colors['Train']),
186                   go.Scatter(x=xs, y=get_density(test_column, xs), fill='tozeroy', name='Test Dataset',
187                              line_color=colors['Test'])]
188 
189         xaxis_layout = dict(fixedrange=False,
190                             range=x_range_to_show,
191                             title='Distribution')
192         yaxis_layout = dict(title='Probability Density', fixedrange=True)
193 
194     return traces, xaxis_layout, yaxis_layout
195
```

Path: `deepchecks/utils/dataframes.py`
Content:
```
1 # ----------------------------------------------------------------------------
2 # Copyright (C) 2021-2022 Deepchecks (https://www.deepchecks.com)
3 #
4 # This file is part of Deepchecks.
5 # Deepchecks is distributed under the terms of the GNU Affero General
6 # Public License (version 3 or later).
7 # You should have received a copy of the GNU Affero General Public License
8 # along with Deepchecks.  If not, see <http://www.gnu.org/licenses/>.
9 # ----------------------------------------------------------------------------
10 #
11 """Contain functions for handling dataframes in checks."""
12 import typing as t
13 import pandas as pd
14 from deepchecks.utils.typing import Hashable
15 from deepchecks.utils.validation import ensure_hashable_or_mutable_sequence
16 from deepchecks.core.errors import DeepchecksValueError
17 
18 
19 __all__ = ['validate_columns_exist', 'select_from_dataframe']
20 
21 
22 def validate_columns_exist(
23     df: pd.DataFrame,
24     columns: t.Union[Hashable, t.List[Hashable]],
25     raise_error: bool = True
26 ) -> bool:
27     """Validate given columns exist in dataframe.
28 
29     Parameters
30     ----------
31     df : pd.DataFrame
32         dataframe to inspect
33     columns : t.Union[Hashable, t.List[Hashable]]
34         Column names to check
35     raise_error : bool, default: True
36         whether to raise an error if some column is not present in the dataframe or not
37 
38     Raises
39     ------
40     DeepchecksValueError
41         If some of the columns do not exist within provided dataframe.
42         If receives empty list of 'columns'.
43         If not all elements within 'columns' list are hashable.
44     """
45     error_message = 'columns - expected to receive not empty list of hashable values!'
46     columns = ensure_hashable_or_mutable_sequence(columns, message=error_message)
47 
48     is_empty = len(columns) == 0
49 
50     if raise_error and is_empty:
51         raise DeepchecksValueError(error_message)
52     elif not raise_error and is_empty:
53         return False
54 
55     difference = set(columns) - set(df.columns)
56     all_columns_present = len(difference) == 0
57 
58     if raise_error and not all_columns_present:
59         stringified_columns = ','.join(map(str, difference))
60         raise DeepchecksValueError(f'Given columns do not exist in dataset: {stringified_columns}')
61 
62     return all_columns_present
63 
64 
65 def select_from_dataframe(
66     df: pd.DataFrame,
67     columns: t.Union[Hashable, t.List[Hashable], None] = None,
68     ignore_columns: t.Union[Hashable, t.List[Hashable], None] = None
69 ) -> pd.DataFrame:
70     """Filter DataFrame columns by given params.
71 
72     Parameters
73     ----------
74     df : pd.DataFrame
75     columns : t.Union[Hashable, t.List[Hashable]] , default: None
76         Column names to keep.
77     ignore_columns : t.Union[Hashable, t.List[Hashable]] , default: None
78         Column names to drop.
79 
80     Returns
81     -------
82     pandas.DataFrame
83         returns horizontally filtered dataframe
84 
85     Raises
86     ------
87     DeepchecksValueError
88         If some columns do not exist within provided dataframe;
89         If 'columns' and 'ignore_columns' arguments is 'None'.
90     """
91     if columns is not None and ignore_columns is not None:
92         raise DeepchecksValueError(
93             'Cannot receive both parameters "columns" and "ignore", '
94             'only one must be used at most'
95         )
96     elif columns is not None:
97         columns = ensure_hashable_or_mutable_sequence(columns)
98         validate_columns_exist(df, columns)
99         return t.cast(pd.DataFrame, df[columns])
100     elif ignore_columns is not None:
101         ignore_columns = ensure_hashable_or_mutable_sequence(ignore_columns)
102         validate_columns_exist(df, ignore_columns)
103         return df.drop(labels=ignore_columns, axis='columns')
104     else:
105         return df
106
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/deepchecks/utils/dataframes.py b/deepchecks/utils/dataframes.py
--- a/deepchecks/utils/dataframes.py
+++ b/deepchecks/utils/dataframes.py
@@ -10,13 +10,37 @@
 #
 """Contain functions for handling dataframes in checks."""
 import typing as t
+
 import pandas as pd
+import numpy as np
+
 from deepchecks.utils.typing import Hashable
 from deepchecks.utils.validation import ensure_hashable_or_mutable_sequence
 from deepchecks.core.errors import DeepchecksValueError
 
 
-__all__ = ['validate_columns_exist', 'select_from_dataframe']
+__all__ = ['validate_columns_exist', 'select_from_dataframe', 'un_numpy']
+
+
+def un_numpy(val):
+    """Convert numpy value to native value.
+
+    Parameters
+    ----------
+    val :
+        The value to convert.
+
+    Returns
+    -------
+        returns the numpy value in a native type.
+    """
+    if isinstance(val, np.bool_):
+        return str(val)
+    if isinstance(val, (np.float64, np.float_)):
+        if np.isnan(val):
+            return None
+        return float(val)
+    return val
 
 
 def validate_columns_exist(
diff --git a/deepchecks/utils/distribution/plot.py b/deepchecks/utils/distribution/plot.py
--- a/deepchecks/utils/distribution/plot.py
+++ b/deepchecks/utils/distribution/plot.py
@@ -20,6 +20,7 @@
 
 from deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins
 from deepchecks.utils.plot import colors
+from deepchecks.utils.dataframes import un_numpy
 
 
 def get_density(data, xs) -> np.ndarray:
@@ -140,6 +141,9 @@
         expected_percents, actual_percents, categories_list = \
             preprocess_2_cat_cols_to_same_bins(dist1=train_column, dist2=test_column,
                                                max_num_categories=max_num_categories)
+        # fixes plotly widget bug with numpy values by converting them to native values
+        # https://github.com/plotly/plotly.py/issues/3470
+        categories_list = [un_numpy(cat) for cat in categories_list]
         cat_df = pd.DataFrame({'Train dataset': expected_percents, 'Test dataset': actual_percents},
                               index=categories_list)
         train_bar = go.Bar(

{"golden_diff": "diff --git a/deepchecks/utils/dataframes.py b/deepchecks/utils/dataframes.py\n--- a/deepchecks/utils/dataframes.py\n+++ b/deepchecks/utils/dataframes.py\n@@ -10,13 +10,37 @@\n #\n \"\"\"Contain functions for handling dataframes in checks.\"\"\"\n import typing as t\n+\n import pandas as pd\n+import numpy as np\n+\n from deepchecks.utils.typing import Hashable\n from deepchecks.utils.validation import ensure_hashable_or_mutable_sequence\n from deepchecks.core.errors import DeepchecksValueError\n \n \n-__all__ = ['validate_columns_exist', 'select_from_dataframe']\n+__all__ = ['validate_columns_exist', 'select_from_dataframe', 'un_numpy']\n+\n+\n+def un_numpy(val):\n+    \"\"\"Convert numpy value to native value.\n+\n+    Parameters\n+    ----------\n+    val :\n+        The value to convert.\n+\n+    Returns\n+    -------\n+        returns the numpy value in a native type.\n+    \"\"\"\n+    if isinstance(val, np.bool_):\n+        return str(val)\n+    if isinstance(val, (np.float64, np.float_)):\n+        if np.isnan(val):\n+            return None\n+        return float(val)\n+    return val\n \n \n def validate_columns_exist(\ndiff --git a/deepchecks/utils/distribution/plot.py b/deepchecks/utils/distribution/plot.py\n--- a/deepchecks/utils/distribution/plot.py\n+++ b/deepchecks/utils/distribution/plot.py\n@@ -20,6 +20,7 @@\n \n from deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins\n from deepchecks.utils.plot import colors\n+from deepchecks.utils.dataframes import un_numpy\n \n \n def get_density(data, xs) -> np.ndarray:\n@@ -140,6 +141,9 @@\n         expected_percents, actual_percents, categories_list = \\\n             preprocess_2_cat_cols_to_same_bins(dist1=train_column, dist2=test_column,\n                                                max_num_categories=max_num_categories)\n+        # fixes plotly widget bug with numpy values by converting them to native values\n+        # https://github.com/plotly/plotly.py/issues/3470\n+        categories_list = [un_numpy(cat) for cat in categories_list]\n         cat_df = pd.DataFrame({'Train dataset': expected_percents, 'Test dataset': actual_percents},\n                               index=categories_list)\n         train_bar = go.Bar(\n", "issue": "[BUG] Calling `save_as_html` can raise an error if the label column is imbalanced and has the type `np.bool_`\n**Describe the bug**\r\nThe error comes from this chart (section \"Train Test Label Drift\"):\r\n![image](https://user-images.githubusercontent.com/17814966/152127072-57de57d7-1030-42e4-b03c-6a2d5e4305ae.png)\r\n\r\nThis bar chart is created whenever the label is imbalanced and drifts between train and test (which is the case with my data).\r\n\r\nThe x axis has the values `False` and `True` with the dtype `np.bool_`. Before saving as HTML, somewhere in the code, this diagram is encoded as JSON. The call to `json.dumps` causes the error. The solution is to convert the problematic data to the regular Python `bool` type.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Run the code below\r\n2. See error: \"TypeError: Object of type bool_ is not JSON serializable\"\r\n\r\n```python\r\nimport pandas as pd\r\nimport numpy as np\r\n\r\nfrom deepchecks import Dataset\r\nfrom deepchecks.suites import train_test_validation\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    # Generate some random data\r\n    # Note that the data type of the generated label is numpy.bool_\r\n    # (in my project, the label column has this type)\r\n    np.random.seed(42)\r\n    training_size = 1000\r\n    training_positive_proportion = 0.01  # Very low proportion to simulate an imbalanced dataset\r\n    testing_size = 100\r\n    testing_positive_proportion = 0.05  # This proportion is different from training to simulate a drift on the label\r\n    training_df = pd.DataFrame({\r\n        \"feature_1\": np.ones(training_size),\r\n        \"label\": np.random.choice(a=[False, True], size=(training_size,), p=[training_positive_proportion, 1 - training_positive_proportion])\r\n    })\r\n    testing_df = pd.DataFrame({\r\n        \"feature_1\": np.ones(testing_size),\r\n        \"label\": np.random.choice(a=[False, True], size=(testing_size,), p=[testing_positive_proportion, 1 - testing_positive_proportion])\r\n    })\r\n\r\n    # Run the train_test_validation suite\r\n    training_ds = Dataset(df=training_df, label=\"label\", features=[\"feature_1\"])\r\n    testing_ds = Dataset(df=testing_df, label=\"label\", features=[\"feature_1\"])\r\n    suite = train_test_validation()\r\n    results = suite.run(train_dataset=training_ds, test_dataset=testing_ds)\r\n\r\n    # Save as HTML, this will raise the following error:\r\n    # \"TypeError: Object of type bool_ is not JSON serializable\"\r\n    results.save_as_html(\"output.html\")\r\n```\r\n\r\n**Expected behavior**\r\nI would expect deepchecks to deal with this internally by converting the legend values to `bool`.\r\n\r\n**Environment (please complete the following information):**\r\n - OS: Ubuntu 20.04 (running on Windows 10 with WSL)\r\n - Python Version: 3.8.10\r\n - Deepchecks Version: 0.4.1\n", "before_files": [{"content": "# ----------------------------------------------------------------------------\n# Copyright (C) 2021-2022 Deepchecks (https://www.deepchecks.com)\n#\n# This file is part of Deepchecks.\n# Deepchecks is distributed under the terms of the GNU Affero General\n# Public License (version 3 or later).\n# You should have received a copy of the GNU Affero General Public License\n# along with Deepchecks.  If not, see <http://www.gnu.org/licenses/>.\n# ----------------------------------------------------------------------------\n#\n\"\"\"A module containing utils for plotting distributions.\"\"\"\nimport numpy as np\nimport pandas as pd\nfrom scipy.stats import gaussian_kde\nimport plotly.graph_objs as go\n\n__all__ = ['feature_distribution_traces', 'drift_score_bar_traces', 'get_density']\n\nfrom typing import List, Union, Dict, Tuple\n\nfrom deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins\nfrom deepchecks.utils.plot import colors\n\n\ndef get_density(data, xs) -> np.ndarray:\n    \"\"\"Get gaussian kde density to plot.\n\n    Parameters\n    ----------\n    data\n        The data used to compute the pdf function.\n    xs : iterable\n        List of x values to plot the computed pdf for.\n    Returns\n    -------\n    np.array\n        The computed pdf values at the points xs.\n    \"\"\"\n    # Is only single value adds noise, otherwise there is singular matrix error\n    if len(np.unique(data)) == 1:\n        data = data + np.random.normal(scale=10 * np.finfo(np.float32).eps, size=len(data))\n    density = gaussian_kde(data)\n    density.covariance_factor = lambda: .25\n    # pylint: disable=protected-access\n    density._compute_covariance()\n    return density(xs)\n\n\ndef drift_score_bar_traces(drift_score: float, bar_max: float = None) -> Tuple[List[go.Bar], Dict, Dict]:\n    \"\"\"Create a traffic light bar traces for drift score.\n\n    Parameters\n    ----------\n    drift_score : float\n        Drift score\n    bar_max : float , default: None\n        Maximum value for the bar\n    Returns\n    -------\n    Tuple[List[go.Bar], Dict, Dict]\n        list of plotly bar traces.\n    \"\"\"\n    traffic_light_colors = [((0, 0.1), '#01B8AA'),\n                            ((0.1, 0.2), '#F2C80F'),\n                            ((0.2, 0.3), '#FE9666'),\n                            ((0.3, 1), '#FD625E')\n                            ]\n\n    bars = []\n\n    for range_tuple, color in traffic_light_colors:\n        if drift_score < range_tuple[0]:\n            break\n\n        bars.append(go.Bar(\n            x=[min(drift_score, range_tuple[1]) - range_tuple[0]],\n            y=['Drift Score'],\n            orientation='h',\n            marker=dict(\n                color=color,\n            ),\n            offsetgroup=0,\n            base=range_tuple[0],\n            showlegend=False\n\n        ))\n\n    bar_stop = max(0.4, drift_score + 0.1)\n    if bar_max:\n        bar_stop = min(bar_stop, bar_max)\n    xaxis = dict(\n        showgrid=False,\n        gridcolor='black',\n        linecolor='black',\n        range=[0, bar_stop],\n        dtick=0.05,\n        fixedrange=True\n    )\n    yaxis = dict(\n        showgrid=False,\n        showline=False,\n        showticklabels=False,\n        zeroline=False,\n        color='black',\n        fixedrange=True\n    )\n\n    return bars, xaxis, yaxis\n\n\ndef feature_distribution_traces(train_column,\n                                test_column,\n                                is_categorical: bool = False,\n                                max_num_categories: int = 10,\n                                quantile_cut: float = 0.02) -> Tuple[List[Union[go.Bar, go.Scatter]], Dict, Dict]:\n    \"\"\"Create traces for comparison between train and test column.\n\n    Parameters\n    ----------\n    train_column\n        Train data used to trace distribution.\n    test_column\n        Test data used to trace distribution.\n    is_categorical : bool , default: False\n        State if column is categorical.\n    max_num_categories : int , default: 10\n        Maximum number of categories to show in plot (default: 10).\n    quantile_cut : float , default: 0.02\n        in which quantile to cut the edges of the plot\n    Returns\n    -------\n    List[Union[go.Bar, go.Scatter]]\n        list of plotly traces.\n    Dict\n        layout of x axis\n    Dict\n        layout of y axis\n    \"\"\"\n    if is_categorical:\n        expected_percents, actual_percents, categories_list = \\\n            preprocess_2_cat_cols_to_same_bins(dist1=train_column, dist2=test_column,\n                                               max_num_categories=max_num_categories)\n        cat_df = pd.DataFrame({'Train dataset': expected_percents, 'Test dataset': actual_percents},\n                              index=categories_list)\n        train_bar = go.Bar(\n            x=cat_df.index,\n            y=cat_df['Train dataset'],\n            marker=dict(\n                color=colors['Train'],\n            ),\n            name='Train Dataset',\n        )\n\n        test_bar = go.Bar(\n            x=cat_df.index,\n            y=cat_df['Test dataset'],\n            marker=dict(\n                color=colors['Test'],\n            ),\n            name='Test Dataset',\n        )\n\n        traces = [train_bar, test_bar]\n\n        xaxis_layout = dict(type='category')\n        yaxis_layout = dict(fixedrange=True,\n                            range=(0, 1),\n                            title='Percentage')\n\n    else:\n        x_range = (min(train_column.min(), test_column.min()), max(train_column.max(), test_column.max()))\n        x_range_to_show = (\n            min(np.quantile(train_column, quantile_cut), np.quantile(test_column, quantile_cut)),\n            max(np.quantile(train_column, 1 - quantile_cut), np.quantile(test_column, 1 - quantile_cut))\n        )\n        # Heuristically take points on x-axis to show on the plot\n        # The intuition is the graph will look \"smooth\" wherever we will zoom it\n        xs = sorted(np.concatenate((\n            np.linspace(x_range[0], x_range[1], 50),\n            np.quantile(train_column, q=np.arange(0.02, 1, 0.02)),\n            np.quantile(test_column, q=np.arange(0.02, 1, 0.02))\n        )))\n\n        traces = [go.Scatter(x=xs, y=get_density(train_column, xs), fill='tozeroy', name='Train Dataset',\n                             line_color=colors['Train']),\n                  go.Scatter(x=xs, y=get_density(test_column, xs), fill='tozeroy', name='Test Dataset',\n                             line_color=colors['Test'])]\n\n        xaxis_layout = dict(fixedrange=False,\n                            range=x_range_to_show,\n                            title='Distribution')\n        yaxis_layout = dict(title='Probability Density', fixedrange=True)\n\n    return traces, xaxis_layout, yaxis_layout\n", "path": "deepchecks/utils/distribution/plot.py"}, {"content": "# ----------------------------------------------------------------------------\n# Copyright (C) 2021-2022 Deepchecks (https://www.deepchecks.com)\n#\n# This file is part of Deepchecks.\n# Deepchecks is distributed under the terms of the GNU Affero General\n# Public License (version 3 or later).\n# You should have received a copy of the GNU Affero General Public License\n# along with Deepchecks.  If not, see <http://www.gnu.org/licenses/>.\n# ----------------------------------------------------------------------------\n#\n\"\"\"Contain functions for handling dataframes in checks.\"\"\"\nimport typing as t\nimport pandas as pd\nfrom deepchecks.utils.typing import Hashable\nfrom deepchecks.utils.validation import ensure_hashable_or_mutable_sequence\nfrom deepchecks.core.errors import DeepchecksValueError\n\n\n__all__ = ['validate_columns_exist', 'select_from_dataframe']\n\n\ndef validate_columns_exist(\n    df: pd.DataFrame,\n    columns: t.Union[Hashable, t.List[Hashable]],\n    raise_error: bool = True\n) -> bool:\n    \"\"\"Validate given columns exist in dataframe.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        dataframe to inspect\n    columns : t.Union[Hashable, t.List[Hashable]]\n        Column names to check\n    raise_error : bool, default: True\n        whether to raise an error if some column is not present in the dataframe or not\n\n    Raises\n    ------\n    DeepchecksValueError\n        If some of the columns do not exist within provided dataframe.\n        If receives empty list of 'columns'.\n        If not all elements within 'columns' list are hashable.\n    \"\"\"\n    error_message = 'columns - expected to receive not empty list of hashable values!'\n    columns = ensure_hashable_or_mutable_sequence(columns, message=error_message)\n\n    is_empty = len(columns) == 0\n\n    if raise_error and is_empty:\n        raise DeepchecksValueError(error_message)\n    elif not raise_error and is_empty:\n        return False\n\n    difference = set(columns) - set(df.columns)\n    all_columns_present = len(difference) == 0\n\n    if raise_error and not all_columns_present:\n        stringified_columns = ','.join(map(str, difference))\n        raise DeepchecksValueError(f'Given columns do not exist in dataset: {stringified_columns}')\n\n    return all_columns_present\n\n\ndef select_from_dataframe(\n    df: pd.DataFrame,\n    columns: t.Union[Hashable, t.List[Hashable], None] = None,\n    ignore_columns: t.Union[Hashable, t.List[Hashable], None] = None\n) -> pd.DataFrame:\n    \"\"\"Filter DataFrame columns by given params.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n    columns : t.Union[Hashable, t.List[Hashable]] , default: None\n        Column names to keep.\n    ignore_columns : t.Union[Hashable, t.List[Hashable]] , default: None\n        Column names to drop.\n\n    Returns\n    -------\n    pandas.DataFrame\n        returns horizontally filtered dataframe\n\n    Raises\n    ------\n    DeepchecksValueError\n        If some columns do not exist within provided dataframe;\n        If 'columns' and 'ignore_columns' arguments is 'None'.\n    \"\"\"\n    if columns is not None and ignore_columns is not None:\n        raise DeepchecksValueError(\n            'Cannot receive both parameters \"columns\" and \"ignore\", '\n            'only one must be used at most'\n        )\n    elif columns is not None:\n        columns = ensure_hashable_or_mutable_sequence(columns)\n        validate_columns_exist(df, columns)\n        return t.cast(pd.DataFrame, df[columns])\n    elif ignore_columns is not None:\n        ignore_columns = ensure_hashable_or_mutable_sequence(ignore_columns)\n        validate_columns_exist(df, ignore_columns)\n        return df.drop(labels=ignore_columns, axis='columns')\n    else:\n        return df\n", "path": "deepchecks/utils/dataframes.py"}], "after_files": [{"content": "# ----------------------------------------------------------------------------\n# Copyright (C) 2021-2022 Deepchecks (https://www.deepchecks.com)\n#\n# This file is part of Deepchecks.\n# Deepchecks is distributed under the terms of the GNU Affero General\n# Public License (version 3 or later).\n# You should have received a copy of the GNU Affero General Public License\n# along with Deepchecks.  If not, see <http://www.gnu.org/licenses/>.\n# ----------------------------------------------------------------------------\n#\n\"\"\"A module containing utils for plotting distributions.\"\"\"\nimport numpy as np\nimport pandas as pd\nfrom scipy.stats import gaussian_kde\nimport plotly.graph_objs as go\n\n__all__ = ['feature_distribution_traces', 'drift_score_bar_traces', 'get_density']\n\nfrom typing import List, Union, Dict, Tuple\n\nfrom deepchecks.utils.distribution.preprocessing import preprocess_2_cat_cols_to_same_bins\nfrom deepchecks.utils.plot import colors\nfrom deepchecks.utils.dataframes import un_numpy\n\n\ndef get_density(data, xs) -> np.ndarray:\n    \"\"\"Get gaussian kde density to plot.\n\n    Parameters\n    ----------\n    data\n        The data used to compute the pdf function.\n    xs : iterable\n        List of x values to plot the computed pdf for.\n    Returns\n    -------\n    np.array\n        The computed pdf values at the points xs.\n    \"\"\"\n    # Is only single value adds noise, otherwise there is singular matrix error\n    if len(np.unique(data)) == 1:\n        data = data + np.random.normal(scale=10 * np.finfo(np.float32).eps, size=len(data))\n    density = gaussian_kde(data)\n    density.covariance_factor = lambda: .25\n    # pylint: disable=protected-access\n    density._compute_covariance()\n    return density(xs)\n\n\ndef drift_score_bar_traces(drift_score: float, bar_max: float = None) -> Tuple[List[go.Bar], Dict, Dict]:\n    \"\"\"Create a traffic light bar traces for drift score.\n\n    Parameters\n    ----------\n    drift_score : float\n        Drift score\n    bar_max : float , default: None\n        Maximum value for the bar\n    Returns\n    -------\n    Tuple[List[go.Bar], Dict, Dict]\n        list of plotly bar traces.\n    \"\"\"\n    traffic_light_colors = [((0, 0.1), '#01B8AA'),\n                            ((0.1, 0.2), '#F2C80F'),\n                            ((0.2, 0.3), '#FE9666'),\n                            ((0.3, 1), '#FD625E')\n                            ]\n\n    bars = []\n\n    for range_tuple, color in traffic_light_colors:\n        if drift_score < range_tuple[0]:\n            break\n\n        bars.append(go.Bar(\n            x=[min(drift_score, range_tuple[1]) - range_tuple[0]],\n            y=['Drift Score'],\n            orientation='h',\n            marker=dict(\n                color=color,\n            ),\n            offsetgroup=0,\n            base=range_tuple[0],\n            showlegend=False\n\n        ))\n\n    bar_stop = max(0.4, drift_score + 0.1)\n    if bar_max:\n        bar_stop = min(bar_stop, bar_max)\n    xaxis = dict(\n        showgrid=False,\n        gridcolor='black',\n        linecolor='black',\n        range=[0, bar_stop],\n        dtick=0.05,\n        fixedrange=True\n    )\n    yaxis = dict(\n        showgrid=False,\n        showline=False,\n        showticklabels=False,\n        zeroline=False,\n        color='black',\n        fixedrange=True\n    )\n\n    return bars, xaxis, yaxis\n\n\ndef feature_distribution_traces(train_column,\n                                test_column,\n                                is_categorical: bool = False,\n                                max_num_categories: int = 10,\n                                quantile_cut: float = 0.02) -> Tuple[List[Union[go.Bar, go.Scatter]], Dict, Dict]:\n    \"\"\"Create traces for comparison between train and test column.\n\n    Parameters\n    ----------\n    train_column\n        Train data used to trace distribution.\n    test_column\n        Test data used to trace distribution.\n    is_categorical : bool , default: False\n        State if column is categorical.\n    max_num_categories : int , default: 10\n        Maximum number of categories to show in plot (default: 10).\n    quantile_cut : float , default: 0.02\n        in which quantile to cut the edges of the plot\n    Returns\n    -------\n    List[Union[go.Bar, go.Scatter]]\n        list of plotly traces.\n    Dict\n        layout of x axis\n    Dict\n        layout of y axis\n    \"\"\"\n    if is_categorical:\n        expected_percents, actual_percents, categories_list = \\\n            preprocess_2_cat_cols_to_same_bins(dist1=train_column, dist2=test_column,\n                                               max_num_categories=max_num_categories)\n        # fixes plotly widget bug with numpy values by converting them to native values\n        # https://github.com/plotly/plotly.py/issues/3470\n        categories_list = [un_numpy(cat) for cat in categories_list]\n        cat_df = pd.DataFrame({'Train dataset': expected_percents, 'Test dataset': actual_percents},\n                              index=categories_list)\n        train_bar = go.Bar(\n            x=cat_df.index,\n            y=cat_df['Train dataset'],\n            marker=dict(\n                color=colors['Train'],\n            ),\n            name='Train Dataset',\n        )\n\n        test_bar = go.Bar(\n            x=cat_df.index,\n            y=cat_df['Test dataset'],\n            marker=dict(\n                color=colors['Test'],\n            ),\n            name='Test Dataset',\n        )\n\n        traces = [train_bar, test_bar]\n\n        xaxis_layout = dict(type='category')\n        yaxis_layout = dict(fixedrange=True,\n                            range=(0, 1),\n                            title='Percentage')\n\n    else:\n        x_range = (min(train_column.min(), test_column.min()), max(train_column.max(), test_column.max()))\n        x_range_to_show = (\n            min(np.quantile(train_column, quantile_cut), np.quantile(test_column, quantile_cut)),\n            max(np.quantile(train_column, 1 - quantile_cut), np.quantile(test_column, 1 - quantile_cut))\n        )\n        # Heuristically take points on x-axis to show on the plot\n        # The intuition is the graph will look \"smooth\" wherever we will zoom it\n        xs = sorted(np.concatenate((\n            np.linspace(x_range[0], x_range[1], 50),\n            np.quantile(train_column, q=np.arange(0.02, 1, 0.02)),\n            np.quantile(test_column, q=np.arange(0.02, 1, 0.02))\n        )))\n\n        traces = [go.Scatter(x=xs, y=get_density(train_column, xs), fill='tozeroy', name='Train Dataset',\n                             line_color=colors['Train']),\n                  go.Scatter(x=xs, y=get_density(test_column, xs), fill='tozeroy', name='Test Dataset',\n                             line_color=colors['Test'])]\n\n        xaxis_layout = dict(fixedrange=False,\n                            range=x_range_to_show,\n                            title='Distribution')\n        yaxis_layout = dict(title='Probability Density', fixedrange=True)\n\n    return traces, xaxis_layout, yaxis_layout\n", "path": "deepchecks/utils/distribution/plot.py"}, {"content": "# ----------------------------------------------------------------------------\n# Copyright (C) 2021-2022 Deepchecks (https://www.deepchecks.com)\n#\n# This file is part of Deepchecks.\n# Deepchecks is distributed under the terms of the GNU Affero General\n# Public License (version 3 or later).\n# You should have received a copy of the GNU Affero General Public License\n# along with Deepchecks.  If not, see <http://www.gnu.org/licenses/>.\n# ----------------------------------------------------------------------------\n#\n\"\"\"Contain functions for handling dataframes in checks.\"\"\"\nimport typing as t\n\nimport pandas as pd\nimport numpy as np\n\nfrom deepchecks.utils.typing import Hashable\nfrom deepchecks.utils.validation import ensure_hashable_or_mutable_sequence\nfrom deepchecks.core.errors import DeepchecksValueError\n\n\n__all__ = ['validate_columns_exist', 'select_from_dataframe', 'un_numpy']\n\n\ndef un_numpy(val):\n    \"\"\"Convert numpy value to native value.\n\n    Parameters\n    ----------\n    val :\n        The value to convert.\n\n    Returns\n    -------\n        returns the numpy value in a native type.\n    \"\"\"\n    if isinstance(val, np.bool_):\n        return str(val)\n    if isinstance(val, (np.float64, np.float_)):\n        if np.isnan(val):\n            return None\n        return float(val)\n    return val\n\n\ndef validate_columns_exist(\n    df: pd.DataFrame,\n    columns: t.Union[Hashable, t.List[Hashable]],\n    raise_error: bool = True\n) -> bool:\n    \"\"\"Validate given columns exist in dataframe.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n        dataframe to inspect\n    columns : t.Union[Hashable, t.List[Hashable]]\n        Column names to check\n    raise_error : bool, default: True\n        whether to raise an error if some column is not present in the dataframe or not\n\n    Raises\n    ------\n    DeepchecksValueError\n        If some of the columns do not exist within provided dataframe.\n        If receives empty list of 'columns'.\n        If not all elements within 'columns' list are hashable.\n    \"\"\"\n    error_message = 'columns - expected to receive not empty list of hashable values!'\n    columns = ensure_hashable_or_mutable_sequence(columns, message=error_message)\n\n    is_empty = len(columns) == 0\n\n    if raise_error and is_empty:\n        raise DeepchecksValueError(error_message)\n    elif not raise_error and is_empty:\n        return False\n\n    difference = set(columns) - set(df.columns)\n    all_columns_present = len(difference) == 0\n\n    if raise_error and not all_columns_present:\n        stringified_columns = ','.join(map(str, difference))\n        raise DeepchecksValueError(f'Given columns do not exist in dataset: {stringified_columns}')\n\n    return all_columns_present\n\n\ndef select_from_dataframe(\n    df: pd.DataFrame,\n    columns: t.Union[Hashable, t.List[Hashable], None] = None,\n    ignore_columns: t.Union[Hashable, t.List[Hashable], None] = None\n) -> pd.DataFrame:\n    \"\"\"Filter DataFrame columns by given params.\n\n    Parameters\n    ----------\n    df : pd.DataFrame\n    columns : t.Union[Hashable, t.List[Hashable]] , default: None\n        Column names to keep.\n    ignore_columns : t.Union[Hashable, t.List[Hashable]] , default: None\n        Column names to drop.\n\n    Returns\n    -------\n    pandas.DataFrame\n        returns horizontally filtered dataframe\n\n    Raises\n    ------\n    DeepchecksValueError\n        If some columns do not exist within provided dataframe;\n        If 'columns' and 'ignore_columns' arguments is 'None'.\n    \"\"\"\n    if columns is not None and ignore_columns is not None:\n        raise DeepchecksValueError(\n            'Cannot receive both parameters \"columns\" and \"ignore\", '\n            'only one must be used at most'\n        )\n    elif columns is not None:\n        columns = ensure_hashable_or_mutable_sequence(columns)\n        validate_columns_exist(df, columns)\n        return t.cast(pd.DataFrame, df[columns])\n    elif ignore_columns is not None:\n        ignore_columns = ensure_hashable_or_mutable_sequence(ignore_columns)\n        validate_columns_exist(df, ignore_columns)\n        return df.drop(labels=ignore_columns, axis='columns')\n    else:\n        return df\n", "path": "deepchecks/utils/dataframes.py"}]}