opengood.py-ml-plot 2.3.0__tar.gz → 2.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 OpenGood
3
+ Copyright (c) 2025-2026 OpenGood
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengood.py_ml_plot
3
- Version: 2.3.0
3
+ Version: 2.6.0
4
4
  Summary: Modules containing reusable functions for machine learning visualization plotting
5
5
  Author-email: OpenGood <ai@opengood.ai>
6
6
  License: MIT License
7
7
 
8
- Copyright (c) 2025 OpenGood
8
+ Copyright (c) 2025-2026 OpenGood
9
9
 
10
10
  Permission is hereby granted, free of charge, to any person obtaining a copy
11
11
  of this software and associated documentation files (the "Software"), to deal
@@ -25,30 +25,34 @@ License: MIT License
25
25
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
26
  SOFTWARE.
27
27
 
28
- Project-URL: Homepage, https://github.com/opengood-aio/py-ml-plot
29
- Project-URL: Documentation, https://github.com/opengood-aio/py-ml-plot
28
+ Project-URL: Homepage, https://github.com/opengood-ai/py-ml-plot
29
+ Project-URL: Documentation, https://github.com/opengood-ai/py-ml-plot
30
30
  Classifier: Programming Language :: Python :: 3
31
31
  Classifier: License :: OSI Approved :: MIT License
32
32
  Classifier: Operating System :: OS Independent
33
33
  Requires-Python: >=3.12
34
34
  Description-Content-Type: text/markdown
35
35
  License-File: LICENSE
36
- Requires-Dist: matplotlib>=3.10.3
37
- Requires-Dist: numpy>=2.3.0rc1
38
- Requires-Dist: pandas>=2.2.3
39
- Requires-Dist: scikit-learn>=1.7.0rc1
36
+ Requires-Dist: matplotlib>=3.11.2
37
+ Requires-Dist: numpy>=2.4.4
38
+ Requires-Dist: pandas>=3.1.0
39
+ Requires-Dist: scikit-learn>=1.9.1
40
+ Provides-Extra: dev
41
+ Requires-Dist: pip-tools>=7.5.3; extra == "dev"
42
+ Requires-Dist: pytest>=9.0.3; extra == "dev"
43
+ Requires-Dist: pytest-cov>=7.1.0; extra == "dev"
40
44
  Dynamic: license-file
41
45
 
42
46
  # Python Machine Learning (ML) Plot
43
47
 
44
- [![Build](https://github.com/opengood-aio/py-ml-plot/workflows/build/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions?query=workflow%3Abuild)
45
- [![Release](https://github.com/opengood-aio/py-ml-plot/workflows/release/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions?query=workflow%3Arelease)
46
- [![CodeQL](https://github.com/opengood-aio/py-ml-plot/actions/workflows/codeql.yml/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions/workflows/codeql.yml)
47
- [![Codecov](https://codecov.io/gh/opengood-aio/py-ml-plot/graph/badge.svg?token=WX6Er5S6Vj)](https://codecov.io/gh/opengood-aio/py-ml-plot)
48
- [![Release Version](https://img.shields.io/github/release/opengood-aio/py-ml-plot.svg)](https://github.com/opengood-aio/py-ml-plot/releases/latest)
48
+ [![Build](https://github.com/opengood-ai/py-ml-plot/workflows/build/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions?query=workflow%3Abuild)
49
+ [![Release](https://github.com/opengood-ai/py-ml-plot/workflows/release/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions?query=workflow%3Arelease)
50
+ [![CodeQL](https://github.com/opengood-ai/py-ml-plot/actions/workflows/codeql.yml/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions/workflows/codeql.yml)
51
+ [![Codecov](https://codecov.io/gh/opengood-ai/py-ml-plot/graph/badge.svg?token=WX6Er5S6Vj)](https://codecov.io/gh/opengood-ai/py-ml-plot)
52
+ [![Release Version](https://img.shields.io/github/release/opengood-ai/py-ml-plot.svg)](https://github.com/opengood-ai/py-ml-plot/releases/latest)
49
53
  [![PyPI](https://img.shields.io/pypi/v/opengood.py-ml-plot)](https://pypi.org/project/opengood.py-ml-plot/)
50
54
  ![Python](https://img.shields.io/pypi/pyversions/opengood.py-ml-plot)
51
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/opengood-aio/py-ml-plot/master/LICENSE)
55
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/opengood-ai/py-ml-plot/master/LICENSE)
52
56
 
53
57
  Modules containing reusable functions for machine learning visualization
54
58
  plotting
@@ -123,15 +127,10 @@ setup_classification_plot(
123
127
  0: {"min": 10, "max": 10, "step": 0.25},
124
128
  1: {"min": 1000, "max": 1000, "step": 0.25},
125
129
  },
126
- feature_scale=lambda x_set, y_set: (
127
- sc.inverse_transform(x_set), y_set
128
- ),
129
- predict=lambda x1, x2: (
130
- classifier.predict(
131
- sc.transform(
132
- np.array([x1.ravel(), x2.ravel()]).T)
133
- ).reshape(x1.shape)
134
- ),
130
+ feature_scale=lambda x_set, y_set: (sc.inverse_transform(x_set), y_set),
131
+ predict=lambda x1, x2: classifier.predict(
132
+ sc.transform(np.array([x1.ravel(), x2.ravel()]).T)
133
+ ).reshape(x1.shape),
135
134
  )
136
135
 
137
136
  plt.show()
@@ -139,7 +138,7 @@ plt.show()
139
138
 
140
139
  ##### Output
141
140
 
142
- ![Setup Classification Plot Visualization](https://raw.githubusercontent.com/opengood-aio/py-ml-plot/main/docs/images/setup-classification-plot-visualization.png)
141
+ ![Setup Classification Plot Visualization](https://raw.githubusercontent.com/opengood-ai/py-ml-plot/main/docs/images/setup-classification-plot-visualization.png)
143
142
 
144
143
  ---
145
144
 
@@ -150,12 +149,12 @@ plt.show()
150
149
  `feature_scale` lambda implementation logic for function
151
150
  `setup_classification_plot` is as follows:
152
151
 
153
- * Inverse feature scaling is invoked via a featuring scaling object, such as
154
- the `StandardScalar` object `sc` created earlier for feature scaling
152
+ * Inverse feature scaling is invoked via a feature scaling object, such as
153
+ the `StandardScaler` object `sc` created earlier for feature scaling
155
154
  * `x_set` and `y_set` are assigned non-feature scaled values of the matrix of
156
155
  features and the dependent variable
157
- * `x_set` values are inverted from their feature-scaled values in `x`
158
- * `y_set` values are not inverted and taken directly from `y`
156
+ * `x_set` values are inverted from their feature-scaled values in `x`
157
+ * `y_set` values are not inverted and taken directly from `y`
159
158
 
160
159
  ###### Predict Lambda Logic
161
160
 
@@ -170,62 +169,65 @@ is as follows:
170
169
  scaling
171
170
  * `ravel` function from the NumPy library is used to flatten a
172
171
  multidimensional array into a one-dimensional array
173
- * `x1` and `x2` are flatten into a 1D array via the `ravel` function
174
- * They are then combined via the `array` function from the NumPy
175
- library into a 2D array
176
- * The result is then reshaped via the `reshape` function to match
177
- the shape of `x1`
172
+ * `x1` and `x2` are flatten into a 1D array via the `ravel` function
173
+ * They are then combined via the `array` function from the NumPy
174
+ library into a 2D array
175
+ * The result is then reshaped via the `reshape` function to match
176
+ the shape of `x1`
178
177
 
179
178
  ###### Setup Plot Visualization Logic
180
179
 
181
180
  Visualization implementation logic for function `setup_classification_plot` is
182
181
  as follows:
183
182
 
184
- * `ListedColormap` class from the Matplotlib library creates an object that
185
- generates a colormap visual from a list of colors
183
+ * If the `meshgrid` dict is not defined, a default set of dict attributes are
184
+ set providing min, max, and step values for each axis:
185
+ * `0` and `1` are used for the keys
186
+ * `10` and `1000` are used for `min` and `max` values
187
+ * `0.25` is used for `step` value
188
+ * If the `feature_scale` lambda is not defined, `x_set` and `y_set` are
189
+ assigned the values of `x` and `y`, respectively
186
190
  * If the `feature_scale` lambda is defined, `x_set` and `y_set` are
187
191
  assigned non-feature scaled values of the matrix of features and the dependent
188
192
  variable from the sets using a feature scaling object, such as the
189
- `StandardScalar` object created earlier for feature scaling
193
+ `StandardScaler` object created earlier for feature scaling
190
194
  * `x_set` values are inverted from their feature-scaled values in `x`
191
195
  * `y_set` values are not inverted and taken directly from `y`
192
- * If the `feature_scale` lambda is not defined, `x_set` and `y_set` are
193
- assigned the values of `x` and `y`, respectively
194
196
  * `meshgrid` function from the NumPy library returns a tuple of coordinate
195
- matrices from coordinate vectors (the ranges for each axis are controlled by
196
- the `meshgrid` dict parameter passed to `setup_classification_plot`).
197
- * Two sets of matrices (`x1` and `x2`) are returned with coordinate vectors
198
- * `x1`
199
- * `arange` function is called with a defined start and stop interval
200
- * `x_set[:, 0]` returns all the rows for feature `x1`
201
- * `start` parameter
202
- * Start of an interval
203
- * `x_set[:, 0].min()` returns the minimum value for feature `x1`
204
- * Value of `10` is subtracted for padding
205
- * `stop` parameter
206
- * End of an interval
207
- * `x_set[:, 0].max()` returns the maximum value for feature `x1`
208
- * Value of `10` is added for padding
209
- * `step` parameter
210
- * Spacing between values
211
- * Value of `0.25` is added for spacing
212
- * `x2`
213
- * `arange` function is called with a defined start and stop interval
214
- * `x_set[:, 1]` returns all the rows for feature `x2`
215
- * `start` parameter
216
- * Start of an interval
217
- * `x_set[:, 1].min()` returns the minimum value for feature `x2`
218
- * Value of `1000` is subtracted for padding
219
- * Value of `1000` is used instead of `10` due to the difference
220
- in scaling for feature `x2` vs. feature `x1`
221
- * `stop` parameter
222
- * End of interval
223
- * `x_set[:, 1].max()` returns the maximum value for feature `x2`
224
- * Value of `1000` is added for padding
225
- * `step` parameter
226
- * Spacing between values
227
- * Value of `0.25` is added for spacing
228
- * The prediction logic implemented in the `preodict` lambda is executed, and
197
+ matrices from coordinate vectors
198
+ * The ranges for each axis are controlled by the `meshgrid` dict parameter
199
+ * Two sets of matrices (`x1` and `x2`) are returned with coordinate vectors
200
+ * `x1`
201
+ * `arange` function is called with a defined start and stop interval
202
+ * `x_set[:, 0]` returns all the rows for feature `x1`
203
+ * `start` parameter
204
+ * Start of an interval
205
+ * `x_set[:, 0].min()` returns the minimum value for feature `x1`
206
+ * Value of `10` is subtracted for padding
207
+ * `stop` parameter
208
+ * End of an interval
209
+ * `x_set[:, 0].max()` returns the maximum value for feature `x1`
210
+ * Value of `10` is added for padding
211
+ * `step` parameter
212
+ * Spacing between values
213
+ * Value of `0.25` is added for spacing
214
+ * `x2`
215
+ * `arange` function is called with a defined start and stop interval
216
+ * `x_set[:, 1]` returns all the rows for feature `x2`
217
+ * `start` parameter
218
+ * Start of an interval
219
+ * `x_set[:, 1].min()` returns the minimum value for feature `x2`
220
+ * Value of `1000` is subtracted for padding
221
+ * Value of `1000` is used instead of `10` due to the difference
222
+ in scaling for feature `x2` vs. feature `x1`
223
+ * `stop` parameter
224
+ * End of interval
225
+ * `x_set[:, 1].max()` returns the maximum value for feature `x2`
226
+ * Value of `1000` is added for padding
227
+ * `step` parameter
228
+ * Spacing between values
229
+ * Value of `0.25` is added for spacing
230
+ * The prediction logic implemented in the `predict` lambda is executed, and
229
231
  the result is assigned to `y_pred`, containing the predictions
230
232
  * `contourf` function from the Matplotlib library is used for creating filled
231
233
  contour plots
@@ -302,32 +304,54 @@ as follows:
302
304
 
303
305
  ## Python Virtual Environment
304
306
 
305
- Create Python virtual environment:
307
+ Create and activate Python virtual environment:
306
308
 
307
309
  ```bash
308
- cd ~/workspace/opengood-aio/py-ml-plot/.venv
309
- python3 -m venv ~/workspace/opengood-aio/py-ml-plot/.venv
310
+ python3 -m venv .venv
310
311
  source .venv/bin/activate
311
312
  ```
312
313
 
313
- ## Install Packages
314
+ ## Install Dependencies
315
+
316
+ Install the package in editable mode with all dependencies:
317
+
318
+ ```bash
319
+ python3 -m pip install -e .
320
+ ```
321
+
322
+ Install with development dependencies (includes `pip-tools`, `pytest`, `pytest-cov`):
314
323
 
315
324
  ```bash
316
- python3 -m pip install matplotlib
317
- python3 -m pip install numpy
318
- python3 -m pip install pandas
319
- python3 -m pip install scikit-learn
325
+ python3 -m pip install -e ".[dev]"
320
326
  ```
321
327
 
322
- ## Create Requirements File
328
+ ## Generate Requirements File
329
+
330
+ Generate a pinned `requirements.txt` file from pyproject.toml:
323
331
 
324
332
  ```bash
325
- pip freeze > requirements.txt
333
+ pip-compile pyproject.toml -o requirements.txt
326
334
  ```
327
335
 
336
+ This creates a `requirements.txt` with exact versions of all dependencies and their transitive dependencies.
337
+
328
338
  ## Run Tests
329
339
 
340
+ Run all tests with coverage:
341
+
330
342
  ```bash
331
343
  python -m pytest tests/
332
344
  ```
333
345
 
346
+ Run tests with verbose output and coverage report:
347
+
348
+ ```bash
349
+ python -m pytest tests/ -v --cov=src.opengood.py_ml_plot --cov-report=term-missing
350
+ ```
351
+
352
+ Run a specific test:
353
+
354
+ ```bash
355
+ python -m pytest tests/py_ml_plot/test_classification_plot.py::TestClassificationPlot::test_logistic_regression_setup_classification_plot_with_shaded_regions
356
+ ```
357
+
@@ -1,13 +1,13 @@
1
1
  # Python Machine Learning (ML) Plot
2
2
 
3
- [![Build](https://github.com/opengood-aio/py-ml-plot/workflows/build/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions?query=workflow%3Abuild)
4
- [![Release](https://github.com/opengood-aio/py-ml-plot/workflows/release/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions?query=workflow%3Arelease)
5
- [![CodeQL](https://github.com/opengood-aio/py-ml-plot/actions/workflows/codeql.yml/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions/workflows/codeql.yml)
6
- [![Codecov](https://codecov.io/gh/opengood-aio/py-ml-plot/graph/badge.svg?token=WX6Er5S6Vj)](https://codecov.io/gh/opengood-aio/py-ml-plot)
7
- [![Release Version](https://img.shields.io/github/release/opengood-aio/py-ml-plot.svg)](https://github.com/opengood-aio/py-ml-plot/releases/latest)
3
+ [![Build](https://github.com/opengood-ai/py-ml-plot/workflows/build/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions?query=workflow%3Abuild)
4
+ [![Release](https://github.com/opengood-ai/py-ml-plot/workflows/release/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions?query=workflow%3Arelease)
5
+ [![CodeQL](https://github.com/opengood-ai/py-ml-plot/actions/workflows/codeql.yml/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions/workflows/codeql.yml)
6
+ [![Codecov](https://codecov.io/gh/opengood-ai/py-ml-plot/graph/badge.svg?token=WX6Er5S6Vj)](https://codecov.io/gh/opengood-ai/py-ml-plot)
7
+ [![Release Version](https://img.shields.io/github/release/opengood-ai/py-ml-plot.svg)](https://github.com/opengood-ai/py-ml-plot/releases/latest)
8
8
  [![PyPI](https://img.shields.io/pypi/v/opengood.py-ml-plot)](https://pypi.org/project/opengood.py-ml-plot/)
9
9
  ![Python](https://img.shields.io/pypi/pyversions/opengood.py-ml-plot)
10
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/opengood-aio/py-ml-plot/master/LICENSE)
10
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/opengood-ai/py-ml-plot/master/LICENSE)
11
11
 
12
12
  Modules containing reusable functions for machine learning visualization
13
13
  plotting
@@ -82,15 +82,10 @@ setup_classification_plot(
82
82
  0: {"min": 10, "max": 10, "step": 0.25},
83
83
  1: {"min": 1000, "max": 1000, "step": 0.25},
84
84
  },
85
- feature_scale=lambda x_set, y_set: (
86
- sc.inverse_transform(x_set), y_set
87
- ),
88
- predict=lambda x1, x2: (
89
- classifier.predict(
90
- sc.transform(
91
- np.array([x1.ravel(), x2.ravel()]).T)
92
- ).reshape(x1.shape)
93
- ),
85
+ feature_scale=lambda x_set, y_set: (sc.inverse_transform(x_set), y_set),
86
+ predict=lambda x1, x2: classifier.predict(
87
+ sc.transform(np.array([x1.ravel(), x2.ravel()]).T)
88
+ ).reshape(x1.shape),
94
89
  )
95
90
 
96
91
  plt.show()
@@ -98,7 +93,7 @@ plt.show()
98
93
 
99
94
  ##### Output
100
95
 
101
- ![Setup Classification Plot Visualization](https://raw.githubusercontent.com/opengood-aio/py-ml-plot/main/docs/images/setup-classification-plot-visualization.png)
96
+ ![Setup Classification Plot Visualization](https://raw.githubusercontent.com/opengood-ai/py-ml-plot/main/docs/images/setup-classification-plot-visualization.png)
102
97
 
103
98
  ---
104
99
 
@@ -109,12 +104,12 @@ plt.show()
109
104
  `feature_scale` lambda implementation logic for function
110
105
  `setup_classification_plot` is as follows:
111
106
 
112
- * Inverse feature scaling is invoked via a featuring scaling object, such as
113
- the `StandardScalar` object `sc` created earlier for feature scaling
107
+ * Inverse feature scaling is invoked via a feature scaling object, such as
108
+ the `StandardScaler` object `sc` created earlier for feature scaling
114
109
  * `x_set` and `y_set` are assigned non-feature scaled values of the matrix of
115
110
  features and the dependent variable
116
- * `x_set` values are inverted from their feature-scaled values in `x`
117
- * `y_set` values are not inverted and taken directly from `y`
111
+ * `x_set` values are inverted from their feature-scaled values in `x`
112
+ * `y_set` values are not inverted and taken directly from `y`
118
113
 
119
114
  ###### Predict Lambda Logic
120
115
 
@@ -129,62 +124,65 @@ is as follows:
129
124
  scaling
130
125
  * `ravel` function from the NumPy library is used to flatten a
131
126
  multidimensional array into a one-dimensional array
132
- * `x1` and `x2` are flatten into a 1D array via the `ravel` function
133
- * They are then combined via the `array` function from the NumPy
134
- library into a 2D array
135
- * The result is then reshaped via the `reshape` function to match
136
- the shape of `x1`
127
+ * `x1` and `x2` are flatten into a 1D array via the `ravel` function
128
+ * They are then combined via the `array` function from the NumPy
129
+ library into a 2D array
130
+ * The result is then reshaped via the `reshape` function to match
131
+ the shape of `x1`
137
132
 
138
133
  ###### Setup Plot Visualization Logic
139
134
 
140
135
  Visualization implementation logic for function `setup_classification_plot` is
141
136
  as follows:
142
137
 
143
- * `ListedColormap` class from the Matplotlib library creates an object that
144
- generates a colormap visual from a list of colors
138
+ * If the `meshgrid` dict is not defined, a default set of dict attributes are
139
+ set providing min, max, and step values for each axis:
140
+ * `0` and `1` are used for the keys
141
+ * `10` and `1000` are used for `min` and `max` values
142
+ * `0.25` is used for `step` value
143
+ * If the `feature_scale` lambda is not defined, `x_set` and `y_set` are
144
+ assigned the values of `x` and `y`, respectively
145
145
  * If the `feature_scale` lambda is defined, `x_set` and `y_set` are
146
146
  assigned non-feature scaled values of the matrix of features and the dependent
147
147
  variable from the sets using a feature scaling object, such as the
148
- `StandardScalar` object created earlier for feature scaling
148
+ `StandardScaler` object created earlier for feature scaling
149
149
  * `x_set` values are inverted from their feature-scaled values in `x`
150
150
  * `y_set` values are not inverted and taken directly from `y`
151
- * If the `feature_scale` lambda is not defined, `x_set` and `y_set` are
152
- assigned the values of `x` and `y`, respectively
153
151
  * `meshgrid` function from the NumPy library returns a tuple of coordinate
154
- matrices from coordinate vectors (the ranges for each axis are controlled by
155
- the `meshgrid` dict parameter passed to `setup_classification_plot`).
156
- * Two sets of matrices (`x1` and `x2`) are returned with coordinate vectors
157
- * `x1`
158
- * `arange` function is called with a defined start and stop interval
159
- * `x_set[:, 0]` returns all the rows for feature `x1`
160
- * `start` parameter
161
- * Start of an interval
162
- * `x_set[:, 0].min()` returns the minimum value for feature `x1`
163
- * Value of `10` is subtracted for padding
164
- * `stop` parameter
165
- * End of an interval
166
- * `x_set[:, 0].max()` returns the maximum value for feature `x1`
167
- * Value of `10` is added for padding
168
- * `step` parameter
169
- * Spacing between values
170
- * Value of `0.25` is added for spacing
171
- * `x2`
172
- * `arange` function is called with a defined start and stop interval
173
- * `x_set[:, 1]` returns all the rows for feature `x2`
174
- * `start` parameter
175
- * Start of an interval
176
- * `x_set[:, 1].min()` returns the minimum value for feature `x2`
177
- * Value of `1000` is subtracted for padding
178
- * Value of `1000` is used instead of `10` due to the difference
179
- in scaling for feature `x2` vs. feature `x1`
180
- * `stop` parameter
181
- * End of interval
182
- * `x_set[:, 1].max()` returns the maximum value for feature `x2`
183
- * Value of `1000` is added for padding
184
- * `step` parameter
185
- * Spacing between values
186
- * Value of `0.25` is added for spacing
187
- * The prediction logic implemented in the `preodict` lambda is executed, and
152
+ matrices from coordinate vectors
153
+ * The ranges for each axis are controlled by the `meshgrid` dict parameter
154
+ * Two sets of matrices (`x1` and `x2`) are returned with coordinate vectors
155
+ * `x1`
156
+ * `arange` function is called with a defined start and stop interval
157
+ * `x_set[:, 0]` returns all the rows for feature `x1`
158
+ * `start` parameter
159
+ * Start of an interval
160
+ * `x_set[:, 0].min()` returns the minimum value for feature `x1`
161
+ * Value of `10` is subtracted for padding
162
+ * `stop` parameter
163
+ * End of an interval
164
+ * `x_set[:, 0].max()` returns the maximum value for feature `x1`
165
+ * Value of `10` is added for padding
166
+ * `step` parameter
167
+ * Spacing between values
168
+ * Value of `0.25` is added for spacing
169
+ * `x2`
170
+ * `arange` function is called with a defined start and stop interval
171
+ * `x_set[:, 1]` returns all the rows for feature `x2`
172
+ * `start` parameter
173
+ * Start of an interval
174
+ * `x_set[:, 1].min()` returns the minimum value for feature `x2`
175
+ * Value of `1000` is subtracted for padding
176
+ * Value of `1000` is used instead of `10` due to the difference
177
+ in scaling for feature `x2` vs. feature `x1`
178
+ * `stop` parameter
179
+ * End of interval
180
+ * `x_set[:, 1].max()` returns the maximum value for feature `x2`
181
+ * Value of `1000` is added for padding
182
+ * `step` parameter
183
+ * Spacing between values
184
+ * Value of `0.25` is added for spacing
185
+ * The prediction logic implemented in the `predict` lambda is executed, and
188
186
  the result is assigned to `y_pred`, containing the predictions
189
187
  * `contourf` function from the Matplotlib library is used for creating filled
190
188
  contour plots
@@ -261,32 +259,54 @@ as follows:
261
259
 
262
260
  ## Python Virtual Environment
263
261
 
264
- Create Python virtual environment:
262
+ Create and activate Python virtual environment:
265
263
 
266
264
  ```bash
267
- cd ~/workspace/opengood-aio/py-ml-plot/.venv
268
- python3 -m venv ~/workspace/opengood-aio/py-ml-plot/.venv
265
+ python3 -m venv .venv
269
266
  source .venv/bin/activate
270
267
  ```
271
268
 
272
- ## Install Packages
269
+ ## Install Dependencies
270
+
271
+ Install the package in editable mode with all dependencies:
272
+
273
+ ```bash
274
+ python3 -m pip install -e .
275
+ ```
276
+
277
+ Install with development dependencies (includes `pip-tools`, `pytest`, `pytest-cov`):
273
278
 
274
279
  ```bash
275
- python3 -m pip install matplotlib
276
- python3 -m pip install numpy
277
- python3 -m pip install pandas
278
- python3 -m pip install scikit-learn
280
+ python3 -m pip install -e ".[dev]"
279
281
  ```
280
282
 
281
- ## Create Requirements File
283
+ ## Generate Requirements File
284
+
285
+ Generate a pinned `requirements.txt` file from pyproject.toml:
282
286
 
283
287
  ```bash
284
- pip freeze > requirements.txt
288
+ pip-compile pyproject.toml -o requirements.txt
285
289
  ```
286
290
 
291
+ This creates a `requirements.txt` with exact versions of all dependencies and their transitive dependencies.
292
+
287
293
  ## Run Tests
288
294
 
295
+ Run all tests with coverage:
296
+
289
297
  ```bash
290
298
  python -m pytest tests/
291
299
  ```
292
300
 
301
+ Run tests with verbose output and coverage report:
302
+
303
+ ```bash
304
+ python -m pytest tests/ -v --cov=src.opengood.py_ml_plot --cov-report=term-missing
305
+ ```
306
+
307
+ Run a specific test:
308
+
309
+ ```bash
310
+ python -m pytest tests/py_ml_plot/test_classification_plot.py::TestClassificationPlot::test_logistic_regression_setup_classification_plot_with_shaded_regions
311
+ ```
312
+
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
- requires = ["setuptools >= 77.0.3", "wheel"]
2
+ requires = ["setuptools >= 82.0.1", "wheel"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opengood.py_ml_plot"
7
- version = "2.3.0"
7
+ version = "2.6.0"
8
8
  description = "Modules containing reusable functions for machine learning visualization plotting"
9
9
  authors = [
10
10
  { name = "OpenGood", email = "ai@opengood.ai" }
@@ -19,18 +19,26 @@ readme = "README.md"
19
19
  license = { file = "LICENSE" }
20
20
 
21
21
  dependencies = [
22
- "matplotlib >= 3.10.3",
23
- "numpy >= 2.3.0rc1",
24
- "pandas >= 2.2.3",
25
- "scikit-learn >= 1.7.0rc1",
22
+ "matplotlib >= 3.11.2",
23
+ "numpy >= 2.4.4",
24
+ "pandas >= 3.1.0",
25
+ "scikit-learn >= 1.9.1",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pip-tools >= 7.5.3",
31
+ "pytest >= 9.0.3",
32
+ "pytest-cov >= 7.1.0",
26
33
  ]
27
34
 
28
35
  [project.urls]
29
- Homepage = "https://github.com/opengood-aio/py-ml-plot"
30
- Documentation = "https://github.com/opengood-aio/py-ml-plot"
36
+ Homepage = "https://github.com/opengood-ai/py-ml-plot"
37
+ Documentation = "https://github.com/opengood-ai/py-ml-plot"
31
38
 
32
39
  [tool.pytest.ini_options]
33
- addopts = "tests/ -v --cov=src.opengood.py_ml_plot --cov-report=xml --cov-fail-under=70"
40
+ addopts = "-v --cov=src.opengood.py_ml_plot --cov-report=xml --cov-fail-under=70"
41
+ testpaths = ["tests"]
34
42
  python_files = "test_*.py"
35
43
  python_functions = "test_*"
36
44
  markers = [
@@ -45,4 +53,3 @@ norecursedirs = [".git", ".tox", ".venv"]
45
53
  filterwarnings = "ignore::DeprecationWarning"
46
54
  log_cli = true
47
55
  log_cli_level = "INFO"
48
-
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengood.py_ml_plot
3
- Version: 2.3.0
3
+ Version: 2.6.0
4
4
  Summary: Modules containing reusable functions for machine learning visualization plotting
5
5
  Author-email: OpenGood <ai@opengood.ai>
6
6
  License: MIT License
7
7
 
8
- Copyright (c) 2025 OpenGood
8
+ Copyright (c) 2025-2026 OpenGood
9
9
 
10
10
  Permission is hereby granted, free of charge, to any person obtaining a copy
11
11
  of this software and associated documentation files (the "Software"), to deal
@@ -25,30 +25,34 @@ License: MIT License
25
25
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
26
  SOFTWARE.
27
27
 
28
- Project-URL: Homepage, https://github.com/opengood-aio/py-ml-plot
29
- Project-URL: Documentation, https://github.com/opengood-aio/py-ml-plot
28
+ Project-URL: Homepage, https://github.com/opengood-ai/py-ml-plot
29
+ Project-URL: Documentation, https://github.com/opengood-ai/py-ml-plot
30
30
  Classifier: Programming Language :: Python :: 3
31
31
  Classifier: License :: OSI Approved :: MIT License
32
32
  Classifier: Operating System :: OS Independent
33
33
  Requires-Python: >=3.12
34
34
  Description-Content-Type: text/markdown
35
35
  License-File: LICENSE
36
- Requires-Dist: matplotlib>=3.10.3
37
- Requires-Dist: numpy>=2.3.0rc1
38
- Requires-Dist: pandas>=2.2.3
39
- Requires-Dist: scikit-learn>=1.7.0rc1
36
+ Requires-Dist: matplotlib>=3.11.2
37
+ Requires-Dist: numpy>=2.4.4
38
+ Requires-Dist: pandas>=3.1.0
39
+ Requires-Dist: scikit-learn>=1.9.1
40
+ Provides-Extra: dev
41
+ Requires-Dist: pip-tools>=7.5.3; extra == "dev"
42
+ Requires-Dist: pytest>=9.0.3; extra == "dev"
43
+ Requires-Dist: pytest-cov>=7.1.0; extra == "dev"
40
44
  Dynamic: license-file
41
45
 
42
46
  # Python Machine Learning (ML) Plot
43
47
 
44
- [![Build](https://github.com/opengood-aio/py-ml-plot/workflows/build/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions?query=workflow%3Abuild)
45
- [![Release](https://github.com/opengood-aio/py-ml-plot/workflows/release/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions?query=workflow%3Arelease)
46
- [![CodeQL](https://github.com/opengood-aio/py-ml-plot/actions/workflows/codeql.yml/badge.svg)](https://github.com/opengood-aio/py-ml-plot/actions/workflows/codeql.yml)
47
- [![Codecov](https://codecov.io/gh/opengood-aio/py-ml-plot/graph/badge.svg?token=WX6Er5S6Vj)](https://codecov.io/gh/opengood-aio/py-ml-plot)
48
- [![Release Version](https://img.shields.io/github/release/opengood-aio/py-ml-plot.svg)](https://github.com/opengood-aio/py-ml-plot/releases/latest)
48
+ [![Build](https://github.com/opengood-ai/py-ml-plot/workflows/build/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions?query=workflow%3Abuild)
49
+ [![Release](https://github.com/opengood-ai/py-ml-plot/workflows/release/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions?query=workflow%3Arelease)
50
+ [![CodeQL](https://github.com/opengood-ai/py-ml-plot/actions/workflows/codeql.yml/badge.svg)](https://github.com/opengood-ai/py-ml-plot/actions/workflows/codeql.yml)
51
+ [![Codecov](https://codecov.io/gh/opengood-ai/py-ml-plot/graph/badge.svg?token=WX6Er5S6Vj)](https://codecov.io/gh/opengood-ai/py-ml-plot)
52
+ [![Release Version](https://img.shields.io/github/release/opengood-ai/py-ml-plot.svg)](https://github.com/opengood-ai/py-ml-plot/releases/latest)
49
53
  [![PyPI](https://img.shields.io/pypi/v/opengood.py-ml-plot)](https://pypi.org/project/opengood.py-ml-plot/)
50
54
  ![Python](https://img.shields.io/pypi/pyversions/opengood.py-ml-plot)
51
- [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/opengood-aio/py-ml-plot/master/LICENSE)
55
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/opengood-ai/py-ml-plot/master/LICENSE)
52
56
 
53
57
  Modules containing reusable functions for machine learning visualization
54
58
  plotting
@@ -123,15 +127,10 @@ setup_classification_plot(
123
127
  0: {"min": 10, "max": 10, "step": 0.25},
124
128
  1: {"min": 1000, "max": 1000, "step": 0.25},
125
129
  },
126
- feature_scale=lambda x_set, y_set: (
127
- sc.inverse_transform(x_set), y_set
128
- ),
129
- predict=lambda x1, x2: (
130
- classifier.predict(
131
- sc.transform(
132
- np.array([x1.ravel(), x2.ravel()]).T)
133
- ).reshape(x1.shape)
134
- ),
130
+ feature_scale=lambda x_set, y_set: (sc.inverse_transform(x_set), y_set),
131
+ predict=lambda x1, x2: classifier.predict(
132
+ sc.transform(np.array([x1.ravel(), x2.ravel()]).T)
133
+ ).reshape(x1.shape),
135
134
  )
136
135
 
137
136
  plt.show()
@@ -139,7 +138,7 @@ plt.show()
139
138
 
140
139
  ##### Output
141
140
 
142
- ![Setup Classification Plot Visualization](https://raw.githubusercontent.com/opengood-aio/py-ml-plot/main/docs/images/setup-classification-plot-visualization.png)
141
+ ![Setup Classification Plot Visualization](https://raw.githubusercontent.com/opengood-ai/py-ml-plot/main/docs/images/setup-classification-plot-visualization.png)
143
142
 
144
143
  ---
145
144
 
@@ -150,12 +149,12 @@ plt.show()
150
149
  `feature_scale` lambda implementation logic for function
151
150
  `setup_classification_plot` is as follows:
152
151
 
153
- * Inverse feature scaling is invoked via a featuring scaling object, such as
154
- the `StandardScalar` object `sc` created earlier for feature scaling
152
+ * Inverse feature scaling is invoked via a feature scaling object, such as
153
+ the `StandardScaler` object `sc` created earlier for feature scaling
155
154
  * `x_set` and `y_set` are assigned non-feature scaled values of the matrix of
156
155
  features and the dependent variable
157
- * `x_set` values are inverted from their feature-scaled values in `x`
158
- * `y_set` values are not inverted and taken directly from `y`
156
+ * `x_set` values are inverted from their feature-scaled values in `x`
157
+ * `y_set` values are not inverted and taken directly from `y`
159
158
 
160
159
  ###### Predict Lambda Logic
161
160
 
@@ -170,62 +169,65 @@ is as follows:
170
169
  scaling
171
170
  * `ravel` function from the NumPy library is used to flatten a
172
171
  multidimensional array into a one-dimensional array
173
- * `x1` and `x2` are flatten into a 1D array via the `ravel` function
174
- * They are then combined via the `array` function from the NumPy
175
- library into a 2D array
176
- * The result is then reshaped via the `reshape` function to match
177
- the shape of `x1`
172
+ * `x1` and `x2` are flatten into a 1D array via the `ravel` function
173
+ * They are then combined via the `array` function from the NumPy
174
+ library into a 2D array
175
+ * The result is then reshaped via the `reshape` function to match
176
+ the shape of `x1`
178
177
 
179
178
  ###### Setup Plot Visualization Logic
180
179
 
181
180
  Visualization implementation logic for function `setup_classification_plot` is
182
181
  as follows:
183
182
 
184
- * `ListedColormap` class from the Matplotlib library creates an object that
185
- generates a colormap visual from a list of colors
183
+ * If the `meshgrid` dict is not defined, a default set of dict attributes are
184
+ set providing min, max, and step values for each axis:
185
+ * `0` and `1` are used for the keys
186
+ * `10` and `1000` are used for `min` and `max` values
187
+ * `0.25` is used for `step` value
188
+ * If the `feature_scale` lambda is not defined, `x_set` and `y_set` are
189
+ assigned the values of `x` and `y`, respectively
186
190
  * If the `feature_scale` lambda is defined, `x_set` and `y_set` are
187
191
  assigned non-feature scaled values of the matrix of features and the dependent
188
192
  variable from the sets using a feature scaling object, such as the
189
- `StandardScalar` object created earlier for feature scaling
193
+ `StandardScaler` object created earlier for feature scaling
190
194
  * `x_set` values are inverted from their feature-scaled values in `x`
191
195
  * `y_set` values are not inverted and taken directly from `y`
192
- * If the `feature_scale` lambda is not defined, `x_set` and `y_set` are
193
- assigned the values of `x` and `y`, respectively
194
196
  * `meshgrid` function from the NumPy library returns a tuple of coordinate
195
- matrices from coordinate vectors (the ranges for each axis are controlled by
196
- the `meshgrid` dict parameter passed to `setup_classification_plot`).
197
- * Two sets of matrices (`x1` and `x2`) are returned with coordinate vectors
198
- * `x1`
199
- * `arange` function is called with a defined start and stop interval
200
- * `x_set[:, 0]` returns all the rows for feature `x1`
201
- * `start` parameter
202
- * Start of an interval
203
- * `x_set[:, 0].min()` returns the minimum value for feature `x1`
204
- * Value of `10` is subtracted for padding
205
- * `stop` parameter
206
- * End of an interval
207
- * `x_set[:, 0].max()` returns the maximum value for feature `x1`
208
- * Value of `10` is added for padding
209
- * `step` parameter
210
- * Spacing between values
211
- * Value of `0.25` is added for spacing
212
- * `x2`
213
- * `arange` function is called with a defined start and stop interval
214
- * `x_set[:, 1]` returns all the rows for feature `x2`
215
- * `start` parameter
216
- * Start of an interval
217
- * `x_set[:, 1].min()` returns the minimum value for feature `x2`
218
- * Value of `1000` is subtracted for padding
219
- * Value of `1000` is used instead of `10` due to the difference
220
- in scaling for feature `x2` vs. feature `x1`
221
- * `stop` parameter
222
- * End of interval
223
- * `x_set[:, 1].max()` returns the maximum value for feature `x2`
224
- * Value of `1000` is added for padding
225
- * `step` parameter
226
- * Spacing between values
227
- * Value of `0.25` is added for spacing
228
- * The prediction logic implemented in the `preodict` lambda is executed, and
197
+ matrices from coordinate vectors
198
+ * The ranges for each axis are controlled by the `meshgrid` dict parameter
199
+ * Two sets of matrices (`x1` and `x2`) are returned with coordinate vectors
200
+ * `x1`
201
+ * `arange` function is called with a defined start and stop interval
202
+ * `x_set[:, 0]` returns all the rows for feature `x1`
203
+ * `start` parameter
204
+ * Start of an interval
205
+ * `x_set[:, 0].min()` returns the minimum value for feature `x1`
206
+ * Value of `10` is subtracted for padding
207
+ * `stop` parameter
208
+ * End of an interval
209
+ * `x_set[:, 0].max()` returns the maximum value for feature `x1`
210
+ * Value of `10` is added for padding
211
+ * `step` parameter
212
+ * Spacing between values
213
+ * Value of `0.25` is added for spacing
214
+ * `x2`
215
+ * `arange` function is called with a defined start and stop interval
216
+ * `x_set[:, 1]` returns all the rows for feature `x2`
217
+ * `start` parameter
218
+ * Start of an interval
219
+ * `x_set[:, 1].min()` returns the minimum value for feature `x2`
220
+ * Value of `1000` is subtracted for padding
221
+ * Value of `1000` is used instead of `10` due to the difference
222
+ in scaling for feature `x2` vs. feature `x1`
223
+ * `stop` parameter
224
+ * End of interval
225
+ * `x_set[:, 1].max()` returns the maximum value for feature `x2`
226
+ * Value of `1000` is added for padding
227
+ * `step` parameter
228
+ * Spacing between values
229
+ * Value of `0.25` is added for spacing
230
+ * The prediction logic implemented in the `predict` lambda is executed, and
229
231
  the result is assigned to `y_pred`, containing the predictions
230
232
  * `contourf` function from the Matplotlib library is used for creating filled
231
233
  contour plots
@@ -302,32 +304,54 @@ as follows:
302
304
 
303
305
  ## Python Virtual Environment
304
306
 
305
- Create Python virtual environment:
307
+ Create and activate Python virtual environment:
306
308
 
307
309
  ```bash
308
- cd ~/workspace/opengood-aio/py-ml-plot/.venv
309
- python3 -m venv ~/workspace/opengood-aio/py-ml-plot/.venv
310
+ python3 -m venv .venv
310
311
  source .venv/bin/activate
311
312
  ```
312
313
 
313
- ## Install Packages
314
+ ## Install Dependencies
315
+
316
+ Install the package in editable mode with all dependencies:
317
+
318
+ ```bash
319
+ python3 -m pip install -e .
320
+ ```
321
+
322
+ Install with development dependencies (includes `pip-tools`, `pytest`, `pytest-cov`):
314
323
 
315
324
  ```bash
316
- python3 -m pip install matplotlib
317
- python3 -m pip install numpy
318
- python3 -m pip install pandas
319
- python3 -m pip install scikit-learn
325
+ python3 -m pip install -e ".[dev]"
320
326
  ```
321
327
 
322
- ## Create Requirements File
328
+ ## Generate Requirements File
329
+
330
+ Generate a pinned `requirements.txt` file from pyproject.toml:
323
331
 
324
332
  ```bash
325
- pip freeze > requirements.txt
333
+ pip-compile pyproject.toml -o requirements.txt
326
334
  ```
327
335
 
336
+ This creates a `requirements.txt` with exact versions of all dependencies and their transitive dependencies.
337
+
328
338
  ## Run Tests
329
339
 
340
+ Run all tests with coverage:
341
+
330
342
  ```bash
331
343
  python -m pytest tests/
332
344
  ```
333
345
 
346
+ Run tests with verbose output and coverage report:
347
+
348
+ ```bash
349
+ python -m pytest tests/ -v --cov=src.opengood.py_ml_plot --cov-report=term-missing
350
+ ```
351
+
352
+ Run a specific test:
353
+
354
+ ```bash
355
+ python -m pytest tests/py_ml_plot/test_classification_plot.py::TestClassificationPlot::test_logistic_regression_setup_classification_plot_with_shaded_regions
356
+ ```
357
+
@@ -0,0 +1,9 @@
1
+ matplotlib>=3.11.2
2
+ numpy>=2.4.4
3
+ pandas>=3.1.0
4
+ scikit-learn>=1.9.1
5
+
6
+ [dev]
7
+ pip-tools>=7.5.3
8
+ pytest>=9.0.3
9
+ pytest-cov>=7.1.0
@@ -1,4 +0,0 @@
1
- matplotlib>=3.10.3
2
- numpy>=2.3.0rc1
3
- pandas>=2.2.3
4
- scikit-learn>=1.7.0rc1