├── .gitattributes ├── .gitignore ├── README.md ├── figures ├── soydata_circular_clusters.png ├── soydata_complex_rectangulars.png ├── soydata_decision_tree1.png ├── soydata_decision_tree2.png ├── soydata_linear_regression.png ├── soydata_lower_triangular.png ├── soydata_lower_triangular_nd.png ├── soydata_multilayer_rectangular_randomlabel.png ├── soydata_multilayer_rectangular_regularlabel.png ├── soydata_multilayer_rectangular_rotated.png ├── soydata_polynomial_linear_regression.png ├── soydata_radal.png ├── soydata_rectangular.png ├── soydata_simple_clusters.png ├── soydata_spiral.png ├── soydata_stepfunction_regression.png ├── soydata_stepwise_linear_regression.png ├── soydata_swissroll.png ├── soydata_timeseries_regression.png ├── soydata_two_layer_radial.png ├── soydata_two_moon.png └── soydata_upper_triangular.png ├── poetry.lock ├── pyproject.toml └── soydata ├── __init__.py ├── data ├── __init__.py ├── base.py ├── classification │ ├── __init__.py │ ├── manifold.py │ ├── recipe.py │ └── spatial.py ├── clustering │ ├── __init__.py │ ├── clustering.py │ └── manifold.py ├── external │ ├── __init__.py │ ├── movielens │ │ ├── .gitignore │ │ ├── __init__.py │ │ └── io.py │ └── utils.py └── regression │ ├── __init__.py │ └── simple.py └── visualize ├── __init__.py ├── bokeh.py ├── plotly.py └── utils.py /.gitattributes: -------------------------------------------------------------------------------- 1 | jupyter/* linguist-vendored 2 | data/* linguist-vendored 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # MacOS 2 | .DS_Store 3 | 4 | # Python 5 | *.pyc 6 | __pycache__/ 7 | dist/ 8 | build/ 9 | *.egg-info/ 10 | venv 11 | 12 | # Experiments 13 | tmp/ 14 | 15 | # Jupyter notebook 16 | .ipynb_checkpoints/ 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Install 2 | 3 | (poetry 1.6.0+) 4 | ``` 5 | poetry install 6 | ``` 7 | 8 | ## Usage 9 | 10 | Generate complex synthetic dataset. 11 | 12 | - Data generator functions are in soydata.data 13 | - Visualization functions are in soydata.visualize. These functions uses Bokeh >= 1.4.0 and Plotly >= 4.3.0 14 | 15 | ```python 16 | from soydata.data import * 17 | from soydata.visualize import * 18 | ``` 19 | 20 | ### Two moon 21 | 22 | ```python 23 | from soydata.data.classification import make_moons 24 | from soydata.visualize import scatterplot 25 | 26 | X, labels = make_moons(n_samples=500, xy_ratio=2.0, x_gap=-0.2, y_gap=0.2, noise=0.1) 27 | p = scatterplot(X, labels=labels, height=400, width=400, title='Two moon') 28 | ``` 29 | 30 | 31 | 32 | ### Spiral 33 | 34 | ```python 35 | from soydata.data.classification import make_spiral 36 | from soydata.visualize import scatterplot 37 | 38 | X, labels = make_spiral(n_samples_per_class=500, n_classes=3, 39 | n_rotations=2.5, gap_between_spiral=0.1, noise=0.2, 40 | gap_between_start_point=0.1, equal_interval=True) 41 | p = scatterplot(X, labels=labels, title='Spiral') 42 | ``` 43 | 44 | 45 | 46 | ### Swiss roll 47 | 48 | ```python 49 | from soydata.data.clustering import make_swiss_roll 50 | # from soydata.visualize import scatterplot3d 51 | 52 | X, colors = make_swiss_roll(n_samples=3000, n_rotations=3, 53 | gap=0.5, thickness=0.0, width=10.0, discretize=True) 54 | # fig = scatterplot3d(X, colors) 55 | ``` 56 | 57 | 58 | 59 | ### Radial 60 | 61 | ```python 62 | from soydata.data import make_radial 63 | from soydata.visualize import scatterplot 64 | 65 | X, labels = make_radial(n_samples_per_cluster=100, n_classes=2, 66 | n_clusters_per_class=3, gap=0.1, equal_proportion=True, 67 | radius_min=0.1, radius_scale=1.0, radius_variance=0.5) 68 | p = scatterplot(X, labels=labels, title='Radial') 69 | ``` 70 | 71 | 72 | 73 | ### Two layer radial 74 | 75 | ```python 76 | from soydata.data.classification import make_two_layer_radial 77 | from soydata.visualize import scatterplot 78 | 79 | X, labels = make_two_layer_radial(n_samples_per_cluster=100, n_classes=2, 80 | n_clusters_per_class=3, gap=0.0, equal_proportion=True) 81 | p = scatterplot(X, labels=labels, title='Two-layer radial') 82 | ``` 83 | 84 | 85 | 86 | ### Rectangular 87 | 88 | ```python 89 | from soydata.data import make_rectangular 90 | from soydata.visualize import scatterplot 91 | 92 | X = make_rectangular(n_samples=500, x_min=0, x_max=10, y_min=0, y_max=10) 93 | p = scatterplot(X, title='Rectangular', size=3) 94 | ``` 95 | 96 | 97 | 98 | ### Triangular 99 | 100 | Upper triangular 101 | 102 | ```python 103 | from soydata.data import make_triangular 104 | from soydata.visualize import scatterplot 105 | 106 | X = make_triangular(n_samples=500, upper=True, x_min=0, x_max=10, y_min=0, y_max=10) 107 | p = scatterplot(X, title='Upper triangular', size=3) 108 | ``` 109 | 110 | 111 | 112 | Lower triangular 113 | 114 | ```python 115 | X = make_triangular(n_samples=500, upper=False, x_min=0, x_max=10, y_min=0, y_max=10) 116 | p = scatterplot(X, title='Lower triangular', size=3) 117 | ``` 118 | 119 | 120 | 121 | Lower triangular with negative direction 122 | 123 | ```python 124 | X = make_triangular(n_samples=500, upper=False, positive_direction=False, 125 | x_min=0, x_max=10, y_min=0, y_max=10) 126 | p = scatterplot(X, title='Lower triangular with negative direction', size=3) 127 | ``` 128 | 129 | 130 | 131 | ### Decision Tree dataset 1 132 | 133 | ```python 134 | from soydata.data.classification import make_predefined_data 135 | from soydata.visualize import scatterplot 136 | 137 | X, labels = make_predefined_data('decision-tree-1', n_samples=2000) 138 | p = scatterplot(X, labels=labels, size=3, title='decision-tree-1') 139 | ``` 140 | 141 | 142 | 143 | ### Decision Tree dataset 2 144 | 145 | ```python 146 | X, labels = make_predefined_data('decision-tree-2', n_samples=2000) 147 | p = scatterplot(X, labels=labels, size=3, title='decision-tree-2') 148 | ``` 149 | 150 | 151 | 152 | ### Composition of rectangulars 153 | 154 | ```python 155 | from soydata.data.classification import make_complex_rectangulars 156 | from soydata.visualize import scatterplot 157 | 158 | X, labels = make_complex_rectangulars(n_samples=3000, n_classes=3, 159 | n_rectangulars=20, volume=0.5, seed=0) 160 | p = scatterplot(X, labels=labels, title='Complex rectangulars (3 classes)', size=3) 161 | ``` 162 | 163 | 164 | 165 | To generate regular patterned data 166 | 167 | ```python 168 | from soydata.data.classification import make_multilayer_rectangulars 169 | from soydata.visualize import scatterplot 170 | 171 | X, labels = make_multilayer_rectangulars(rec_size=100, n_layers=3) 172 | p = scatterplot(X, labels=labels, title='Multilayer rectangulars') 173 | ``` 174 | 175 | 176 | 177 | To generate randomly labeled data 178 | 179 | ```python 180 | from soydata.data.classification import make_multilayer_rectangulars 181 | from soydata.visualize import scatterplot 182 | 183 | X, labels = make_multilayer_rectangulars(n_layers=5, random_label=True, n_classes=5) 184 | p = scatterplot(X, labels=labels, title='Random-labeled multilayer rectangulars') 185 | ``` 186 | 187 | 188 | 189 | To generate rotated rectangular data 190 | 191 | ```python 192 | import numpy as np 193 | from soydata.data.classification import make_multilayer_rectangulars 194 | from soydata.visualize import scatterplot 195 | 196 | X, labels = make_multilayer_rectangulars(n_layers=5, random_label=True, n_classes=5, rotate_radian=np.pi/4) 197 | p = scatterplot(X, labels=labels, title='Randomly labeled multi-layer rectangulars (rotated 45)') 198 | ``` 199 | 200 | 201 | 202 | If you want to rotate some other 2D data 203 | 204 | ```python 205 | import numpy as np 206 | from soydata.data import rotate 207 | 208 | X_ = rotate(X, radian=np.pi/4) 209 | ``` 210 | 211 | ### Simple clusters 212 | 213 | ```python 214 | from soydata.data.clustering import make_rectangular_clusters 215 | from soydata.visualize import scatterplot 216 | 217 | X, labels = make_rectangular_clusters(n_clusters=8, 218 | size_min=10, size_max=15, volume=0.2, seed=0) 219 | p = scatterplot(X, labels=labels, title='Simple clusters') 220 | ``` 221 | 222 | 223 | 224 | ```python 225 | import numpy as np 226 | from soydata.data.clustering.clustering import make_circular_clusters 227 | from soydata.visualize import scatterplot 228 | 229 | X, labels = make_circular_clusters(n_clusters=10, r_min=0.05, r_max=0.15, 230 | equal_density=True, noise=0.05, seed=0) 231 | 232 | data_indices = np.where(labels >= 0)[0] 233 | noise_indices = np.where(labels == -1)[0] 234 | 235 | p = scatterplot(X[data_indices], labels=labels, size=3, title='Circular clusters', 236 | show_inline=False, toolbar_location=None) 237 | p = scatterplot(X[noise_indices], p=p, color='lightgrey') 238 | ``` 239 | 240 | 241 | 242 | ### Linear regression 243 | 244 | ```python 245 | from soydata.data.regression import make_linear_regression_data 246 | from soydata.visualize import lineplot 247 | 248 | x, y, y_true = make_linear_regression_data(n_samples=300, x_range=(-1,1), noise=0.5) 249 | p = lineplot(x, y, show_inline=False, line_width=2, title='linear regression') 250 | # overlay true line 251 | p = lineplot(x, y_true, p=p, line_color='red') 252 | ``` 253 | 254 | 255 | 256 | ### Polynomial linear regression 257 | 258 | ```python 259 | from soydata.data.regression import make_polynomial_regression_data 260 | from soydata.visualize import lineplot 261 | 262 | x, y, y_true = make_polynomial_regression_data(degree=5, noise=0.2, seed=11, x_range=(-1.5, 1.5)) 263 | p = lineplot(x, y, show_inline=False, line_width=2, title='Polynomial regression') 264 | p = lineplot(x, y_true, p=p, line_color='red') 265 | ``` 266 | 267 | 268 | 269 | ### Randomwalk regression 270 | 271 | ```python 272 | from soydata.data.regression import make_randomwalk_timeseries_data 273 | from soydata.visualize import scatterplot 274 | 275 | x, y, y_true = make_randomwalk_timeseries_data(n_repeats=3, noise=0.1, std=10, seed=0) 276 | p = scatterplot(x, y, size=3, height=200) 277 | ``` 278 | 279 | 280 | 281 | ### Stepwise linear regression 282 | 283 | ```python 284 | from soydata.data.regression import make_stepwise_regression_data 285 | from soydata.visualize import scatterplot 286 | 287 | x, y, y_true = make_stepwise_regression_data(n_steps=5, noise=0.1, seed=5) 288 | p = scatterplot(x, y, size=3, height=400, width=800, title='Stepwise regression') 289 | ``` 290 | 291 | 292 | 293 | ### Step function for regression 294 | 295 | ```python 296 | from soydata.data.regression import make_stepwise_regression_data 297 | from soydata.visualize import scatterplot 298 | 299 | x, y, y_true = make_stepwise_regression_data(n_steps=5, noise=0.1, seed=5) 300 | p = scatterplot(x, y, size=3, height=400, width=800, title='Stepwise regression') 301 | ``` 302 | 303 | 304 | -------------------------------------------------------------------------------- /figures/soydata_circular_clusters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_circular_clusters.png -------------------------------------------------------------------------------- /figures/soydata_complex_rectangulars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_complex_rectangulars.png -------------------------------------------------------------------------------- /figures/soydata_decision_tree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_decision_tree1.png -------------------------------------------------------------------------------- /figures/soydata_decision_tree2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_decision_tree2.png -------------------------------------------------------------------------------- /figures/soydata_linear_regression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_linear_regression.png -------------------------------------------------------------------------------- /figures/soydata_lower_triangular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_lower_triangular.png -------------------------------------------------------------------------------- /figures/soydata_lower_triangular_nd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_lower_triangular_nd.png -------------------------------------------------------------------------------- /figures/soydata_multilayer_rectangular_randomlabel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_multilayer_rectangular_randomlabel.png -------------------------------------------------------------------------------- /figures/soydata_multilayer_rectangular_regularlabel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_multilayer_rectangular_regularlabel.png -------------------------------------------------------------------------------- /figures/soydata_multilayer_rectangular_rotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_multilayer_rectangular_rotated.png -------------------------------------------------------------------------------- /figures/soydata_polynomial_linear_regression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_polynomial_linear_regression.png -------------------------------------------------------------------------------- /figures/soydata_radal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_radal.png -------------------------------------------------------------------------------- /figures/soydata_rectangular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_rectangular.png -------------------------------------------------------------------------------- /figures/soydata_simple_clusters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_simple_clusters.png -------------------------------------------------------------------------------- /figures/soydata_spiral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_spiral.png -------------------------------------------------------------------------------- /figures/soydata_stepfunction_regression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_stepfunction_regression.png -------------------------------------------------------------------------------- /figures/soydata_stepwise_linear_regression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_stepwise_linear_regression.png -------------------------------------------------------------------------------- /figures/soydata_swissroll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_swissroll.png -------------------------------------------------------------------------------- /figures/soydata_timeseries_regression.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_timeseries_regression.png -------------------------------------------------------------------------------- /figures/soydata_two_layer_radial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_two_layer_radial.png -------------------------------------------------------------------------------- /figures/soydata_two_moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_two_moon.png -------------------------------------------------------------------------------- /figures/soydata_upper_triangular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/figures/soydata_upper_triangular.png -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "black" 5 | version = "23.7.0" 6 | description = "The uncompromising code formatter." 7 | optional = false 8 | python-versions = ">=3.8" 9 | files = [ 10 | {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, 11 | {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, 12 | {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, 13 | {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, 14 | {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, 15 | {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, 16 | {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, 17 | {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, 18 | {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, 19 | {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, 20 | {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, 21 | {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, 22 | {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, 23 | {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, 24 | {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, 25 | {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, 26 | {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, 27 | {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, 28 | {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, 29 | {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, 30 | {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, 31 | {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, 32 | ] 33 | 34 | [package.dependencies] 35 | click = ">=8.0.0" 36 | mypy-extensions = ">=0.4.3" 37 | packaging = ">=22.0" 38 | pathspec = ">=0.9.0" 39 | platformdirs = ">=2" 40 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 41 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 42 | 43 | [package.extras] 44 | colorama = ["colorama (>=0.4.3)"] 45 | d = ["aiohttp (>=3.7.4)"] 46 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 47 | uvloop = ["uvloop (>=0.15.2)"] 48 | 49 | [[package]] 50 | name = "bokeh" 51 | version = "3.2.2" 52 | description = "Interactive plots and applications in the browser from Python" 53 | optional = false 54 | python-versions = ">=3.9" 55 | files = [ 56 | {file = "bokeh-3.2.2-py3-none-any.whl", hash = "sha256:e31670a013e1ff15c3d4d04f587c8162c4cc9fe1af507fd741d295e6c4e1225b"}, 57 | {file = "bokeh-3.2.2.tar.gz", hash = "sha256:b2959b8524d69ec4e7886bc36407445f0a92e1f19530d3bfc4045236a1b7a6ff"}, 58 | ] 59 | 60 | [package.dependencies] 61 | contourpy = ">=1" 62 | Jinja2 = ">=2.9" 63 | numpy = ">=1.16" 64 | packaging = ">=16.8" 65 | pandas = ">=1.2" 66 | pillow = ">=7.1.0" 67 | PyYAML = ">=3.10" 68 | tornado = ">=5.1" 69 | xyzservices = ">=2021.09.1" 70 | 71 | [[package]] 72 | name = "click" 73 | version = "8.1.7" 74 | description = "Composable command line interface toolkit" 75 | optional = false 76 | python-versions = ">=3.7" 77 | files = [ 78 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, 79 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, 80 | ] 81 | 82 | [package.dependencies] 83 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 84 | 85 | [[package]] 86 | name = "colorama" 87 | version = "0.4.6" 88 | description = "Cross-platform colored terminal text." 89 | optional = false 90 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 91 | files = [ 92 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 93 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 94 | ] 95 | 96 | [[package]] 97 | name = "contourpy" 98 | version = "1.1.0" 99 | description = "Python library for calculating contours of 2D quadrilateral grids" 100 | optional = false 101 | python-versions = ">=3.8" 102 | files = [ 103 | {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, 104 | {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, 105 | {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, 106 | {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, 107 | {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, 108 | {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, 109 | {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, 110 | {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, 111 | {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, 112 | {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, 113 | {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, 114 | {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, 115 | {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, 116 | {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, 117 | {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, 118 | {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, 119 | {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, 120 | {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, 121 | {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, 122 | {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, 123 | {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, 124 | {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, 125 | {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, 126 | {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, 127 | {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, 128 | {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, 129 | {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, 130 | {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, 131 | {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, 132 | {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, 133 | {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, 134 | {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, 135 | {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, 136 | {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, 137 | {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, 138 | {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, 139 | {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, 140 | {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, 141 | {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, 142 | ] 143 | 144 | [package.dependencies] 145 | numpy = ">=1.16" 146 | 147 | [package.extras] 148 | bokeh = ["bokeh", "selenium"] 149 | docs = ["furo", "sphinx-copybutton"] 150 | mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] 151 | test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] 152 | test-no-images = ["pytest", "pytest-cov", "wurlitzer"] 153 | 154 | [[package]] 155 | name = "distlib" 156 | version = "0.3.7" 157 | description = "Distribution utilities" 158 | optional = false 159 | python-versions = "*" 160 | files = [ 161 | {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, 162 | {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, 163 | ] 164 | 165 | [[package]] 166 | name = "filelock" 167 | version = "3.12.3" 168 | description = "A platform independent file lock." 169 | optional = false 170 | python-versions = ">=3.8" 171 | files = [ 172 | {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"}, 173 | {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"}, 174 | ] 175 | 176 | [package.dependencies] 177 | typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""} 178 | 179 | [package.extras] 180 | docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] 181 | testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] 182 | 183 | [[package]] 184 | name = "flake8" 185 | version = "6.0.0" 186 | description = "the modular source code checker: pep8 pyflakes and co" 187 | optional = false 188 | python-versions = ">=3.8.1" 189 | files = [ 190 | {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, 191 | {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, 192 | ] 193 | 194 | [package.dependencies] 195 | mccabe = ">=0.7.0,<0.8.0" 196 | pycodestyle = ">=2.10.0,<2.11.0" 197 | pyflakes = ">=3.0.0,<3.1.0" 198 | 199 | [[package]] 200 | name = "importlib-metadata" 201 | version = "6.7.0" 202 | description = "Read metadata from Python packages" 203 | optional = false 204 | python-versions = ">=3.7" 205 | files = [ 206 | {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, 207 | {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, 208 | ] 209 | 210 | [package.dependencies] 211 | zipp = ">=0.5" 212 | 213 | [package.extras] 214 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 215 | perf = ["ipython"] 216 | testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] 217 | 218 | [[package]] 219 | name = "jinja2" 220 | version = "3.1.2" 221 | description = "A very fast and expressive template engine." 222 | optional = false 223 | python-versions = ">=3.7" 224 | files = [ 225 | {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, 226 | {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, 227 | ] 228 | 229 | [package.dependencies] 230 | MarkupSafe = ">=2.0" 231 | 232 | [package.extras] 233 | i18n = ["Babel (>=2.7)"] 234 | 235 | [[package]] 236 | name = "markupsafe" 237 | version = "2.1.3" 238 | description = "Safely add untrusted strings to HTML/XML markup." 239 | optional = false 240 | python-versions = ">=3.7" 241 | files = [ 242 | {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, 243 | {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, 244 | {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, 245 | {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, 246 | {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, 247 | {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, 248 | {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, 249 | {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, 250 | {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, 251 | {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, 252 | {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, 253 | {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, 254 | {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, 255 | {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, 256 | {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, 257 | {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, 258 | {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, 259 | {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, 260 | {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, 261 | {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, 262 | {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, 263 | {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, 264 | {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, 265 | {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, 266 | {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, 267 | {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, 268 | {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, 269 | {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, 270 | {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, 271 | {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, 272 | {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, 273 | {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, 274 | {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, 275 | {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, 276 | {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, 277 | {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, 278 | {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, 279 | {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, 280 | {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, 281 | {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, 282 | {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, 283 | {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, 284 | {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, 285 | {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, 286 | {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, 287 | {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, 288 | {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, 289 | {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, 290 | {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, 291 | {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, 292 | ] 293 | 294 | [[package]] 295 | name = "mccabe" 296 | version = "0.7.0" 297 | description = "McCabe checker, plugin for flake8" 298 | optional = false 299 | python-versions = ">=3.6" 300 | files = [ 301 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, 302 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, 303 | ] 304 | 305 | [[package]] 306 | name = "mypy" 307 | version = "1.4.1" 308 | description = "Optional static typing for Python" 309 | optional = false 310 | python-versions = ">=3.7" 311 | files = [ 312 | {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, 313 | {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, 314 | {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, 315 | {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, 316 | {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, 317 | {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, 318 | {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, 319 | {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, 320 | {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, 321 | {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, 322 | {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, 323 | {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, 324 | {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, 325 | {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, 326 | {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, 327 | {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, 328 | {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, 329 | {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, 330 | {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, 331 | {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, 332 | {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, 333 | {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, 334 | {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, 335 | {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, 336 | {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, 337 | {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, 338 | ] 339 | 340 | [package.dependencies] 341 | mypy-extensions = ">=1.0.0" 342 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 343 | typing-extensions = ">=4.1.0" 344 | 345 | [package.extras] 346 | dmypy = ["psutil (>=4.0)"] 347 | install-types = ["pip"] 348 | python2 = ["typed-ast (>=1.4.0,<2)"] 349 | reports = ["lxml"] 350 | 351 | [[package]] 352 | name = "mypy-extensions" 353 | version = "1.0.0" 354 | description = "Type system extensions for programs checked with the mypy type checker." 355 | optional = false 356 | python-versions = ">=3.5" 357 | files = [ 358 | {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, 359 | {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, 360 | ] 361 | 362 | [[package]] 363 | name = "numpy" 364 | version = "1.25.2" 365 | description = "Fundamental package for array computing in Python" 366 | optional = false 367 | python-versions = ">=3.9" 368 | files = [ 369 | {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, 370 | {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, 371 | {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, 372 | {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, 373 | {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, 374 | {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, 375 | {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, 376 | {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, 377 | {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, 378 | {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, 379 | {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, 380 | {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, 381 | {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, 382 | {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, 383 | {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, 384 | {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, 385 | {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, 386 | {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, 387 | {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, 388 | {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, 389 | {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, 390 | {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, 391 | {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, 392 | {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, 393 | {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, 394 | ] 395 | 396 | [[package]] 397 | name = "packaging" 398 | version = "23.1" 399 | description = "Core utilities for Python packages" 400 | optional = false 401 | python-versions = ">=3.7" 402 | files = [ 403 | {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, 404 | {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, 405 | ] 406 | 407 | [[package]] 408 | name = "pandas" 409 | version = "2.1.0" 410 | description = "Powerful data structures for data analysis, time series, and statistics" 411 | optional = false 412 | python-versions = ">=3.9" 413 | files = [ 414 | {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, 415 | {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, 416 | {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, 417 | {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, 418 | {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, 419 | {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, 420 | {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, 421 | {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, 422 | {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, 423 | {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, 424 | {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, 425 | {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, 426 | {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, 427 | {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, 428 | {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, 429 | {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, 430 | {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, 431 | {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, 432 | {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, 433 | ] 434 | 435 | [package.dependencies] 436 | numpy = [ 437 | {version = ">=1.22.4", markers = "python_version < \"3.11\""}, 438 | {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, 439 | ] 440 | python-dateutil = ">=2.8.2" 441 | pytz = ">=2020.1" 442 | tzdata = ">=2022.1" 443 | 444 | [package.extras] 445 | all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] 446 | aws = ["s3fs (>=2022.05.0)"] 447 | clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] 448 | compression = ["zstandard (>=0.17.0)"] 449 | computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] 450 | consortium-standard = ["dataframe-api-compat (>=0.1.7)"] 451 | excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] 452 | feather = ["pyarrow (>=7.0.0)"] 453 | fss = ["fsspec (>=2022.05.0)"] 454 | gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] 455 | hdf5 = ["tables (>=3.7.0)"] 456 | html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] 457 | mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] 458 | output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] 459 | parquet = ["pyarrow (>=7.0.0)"] 460 | performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] 461 | plot = ["matplotlib (>=3.6.1)"] 462 | postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] 463 | spss = ["pyreadstat (>=1.1.5)"] 464 | sql-other = ["SQLAlchemy (>=1.4.36)"] 465 | test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] 466 | xml = ["lxml (>=4.8.0)"] 467 | 468 | [[package]] 469 | name = "pathspec" 470 | version = "0.11.2" 471 | description = "Utility library for gitignore style pattern matching of file paths." 472 | optional = false 473 | python-versions = ">=3.7" 474 | files = [ 475 | {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, 476 | {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, 477 | ] 478 | 479 | [[package]] 480 | name = "pillow" 481 | version = "10.0.0" 482 | description = "Python Imaging Library (Fork)" 483 | optional = false 484 | python-versions = ">=3.8" 485 | files = [ 486 | {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, 487 | {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, 488 | {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, 489 | {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, 490 | {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, 491 | {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, 492 | {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, 493 | {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, 494 | {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, 495 | {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, 496 | {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, 497 | {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, 498 | {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, 499 | {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, 500 | {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, 501 | {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, 502 | {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, 503 | {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, 504 | {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, 505 | {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, 506 | {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, 507 | {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, 508 | {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, 509 | {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, 510 | {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, 511 | {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, 512 | {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, 513 | {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, 514 | {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, 515 | {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, 516 | {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, 517 | {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, 518 | {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, 519 | {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, 520 | {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, 521 | {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, 522 | {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, 523 | {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, 524 | {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, 525 | {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, 526 | {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, 527 | {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, 528 | {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, 529 | {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, 530 | {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, 531 | {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, 532 | {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, 533 | {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, 534 | {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, 535 | {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, 536 | {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, 537 | {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, 538 | {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, 539 | {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, 540 | {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, 541 | {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, 542 | ] 543 | 544 | [package.extras] 545 | docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] 546 | tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] 547 | 548 | [[package]] 549 | name = "platformdirs" 550 | version = "3.10.0" 551 | description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 552 | optional = false 553 | python-versions = ">=3.7" 554 | files = [ 555 | {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, 556 | {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, 557 | ] 558 | 559 | [package.extras] 560 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] 561 | test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] 562 | 563 | [[package]] 564 | name = "plotly" 565 | version = "4.3.0" 566 | description = "An open-source, interactive graphing library for Python" 567 | optional = false 568 | python-versions = "*" 569 | files = [ 570 | {file = "plotly-4.3.0-py2.py3-none-any.whl", hash = "sha256:1950a5be28caddea3a41d41016750ddf5a602952efb423b39c73adafe6876492"}, 571 | {file = "plotly-4.3.0.tar.gz", hash = "sha256:bd6f453efa171dcea32fd08ad981712829f3dba4509603b3c3b8683b140ef30b"}, 572 | ] 573 | 574 | [package.dependencies] 575 | retrying = ">=1.3.3" 576 | six = "*" 577 | 578 | [[package]] 579 | name = "pluggy" 580 | version = "1.3.0" 581 | description = "plugin and hook calling mechanisms for python" 582 | optional = false 583 | python-versions = ">=3.8" 584 | files = [ 585 | {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, 586 | {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, 587 | ] 588 | 589 | [package.extras] 590 | dev = ["pre-commit", "tox"] 591 | testing = ["pytest", "pytest-benchmark"] 592 | 593 | [[package]] 594 | name = "py" 595 | version = "1.11.0" 596 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 597 | optional = false 598 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 599 | files = [ 600 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 601 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 602 | ] 603 | 604 | [[package]] 605 | name = "pycodestyle" 606 | version = "2.10.0" 607 | description = "Python style guide checker" 608 | optional = false 609 | python-versions = ">=3.6" 610 | files = [ 611 | {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, 612 | {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, 613 | ] 614 | 615 | [[package]] 616 | name = "pyflakes" 617 | version = "3.0.1" 618 | description = "passive checker of Python programs" 619 | optional = false 620 | python-versions = ">=3.6" 621 | files = [ 622 | {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, 623 | {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, 624 | ] 625 | 626 | [[package]] 627 | name = "python-dateutil" 628 | version = "2.8.2" 629 | description = "Extensions to the standard Python datetime module" 630 | optional = false 631 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 632 | files = [ 633 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, 634 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, 635 | ] 636 | 637 | [package.dependencies] 638 | six = ">=1.5" 639 | 640 | [[package]] 641 | name = "pytz" 642 | version = "2023.3" 643 | description = "World timezone definitions, modern and historical" 644 | optional = false 645 | python-versions = "*" 646 | files = [ 647 | {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, 648 | {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, 649 | ] 650 | 651 | [[package]] 652 | name = "pyyaml" 653 | version = "6.0.1" 654 | description = "YAML parser and emitter for Python" 655 | optional = false 656 | python-versions = ">=3.6" 657 | files = [ 658 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, 659 | {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, 660 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, 661 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, 662 | {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, 663 | {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, 664 | {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, 665 | {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, 666 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, 667 | {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, 668 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, 669 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, 670 | {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, 671 | {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, 672 | {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, 673 | {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, 674 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, 675 | {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, 676 | {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, 677 | {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, 678 | {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, 679 | {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, 680 | {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, 681 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, 682 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, 683 | {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, 684 | {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, 685 | {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, 686 | {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, 687 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, 688 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, 689 | {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, 690 | {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, 691 | {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, 692 | {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, 693 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, 694 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, 695 | {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, 696 | {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, 697 | {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, 698 | {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, 699 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, 700 | {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, 701 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, 702 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, 703 | {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, 704 | {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, 705 | {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, 706 | {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, 707 | {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, 708 | ] 709 | 710 | [[package]] 711 | name = "retrying" 712 | version = "1.3.4" 713 | description = "Retrying" 714 | optional = false 715 | python-versions = "*" 716 | files = [ 717 | {file = "retrying-1.3.4-py3-none-any.whl", hash = "sha256:8cc4d43cb8e1125e0ff3344e9de678fefd85db3b750b81b2240dc0183af37b35"}, 718 | {file = "retrying-1.3.4.tar.gz", hash = "sha256:345da8c5765bd982b1d1915deb9102fd3d1f7ad16bd84a9700b85f64d24e8f3e"}, 719 | ] 720 | 721 | [package.dependencies] 722 | six = ">=1.7.0" 723 | 724 | [[package]] 725 | name = "six" 726 | version = "1.16.0" 727 | description = "Python 2 and 3 compatibility utilities" 728 | optional = false 729 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 730 | files = [ 731 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 732 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 733 | ] 734 | 735 | [[package]] 736 | name = "tomli" 737 | version = "2.0.1" 738 | description = "A lil' TOML parser" 739 | optional = false 740 | python-versions = ">=3.7" 741 | files = [ 742 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 743 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 744 | ] 745 | 746 | [[package]] 747 | name = "tornado" 748 | version = "6.3.3" 749 | description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." 750 | optional = false 751 | python-versions = ">= 3.8" 752 | files = [ 753 | {file = "tornado-6.3.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:502fba735c84450974fec147340016ad928d29f1e91f49be168c0a4c18181e1d"}, 754 | {file = "tornado-6.3.3-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:805d507b1f588320c26f7f097108eb4023bbaa984d63176d1652e184ba24270a"}, 755 | {file = "tornado-6.3.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd19ca6c16882e4d37368e0152f99c099bad93e0950ce55e71daed74045908f"}, 756 | {file = "tornado-6.3.3-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ac51f42808cca9b3613f51ffe2a965c8525cb1b00b7b2d56828b8045354f76a"}, 757 | {file = "tornado-6.3.3-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71a8db65160a3c55d61839b7302a9a400074c9c753040455494e2af74e2501f2"}, 758 | {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ceb917a50cd35882b57600709dd5421a418c29ddc852da8bcdab1f0db33406b0"}, 759 | {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:7d01abc57ea0dbb51ddfed477dfe22719d376119844e33c661d873bf9c0e4a16"}, 760 | {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9dc4444c0defcd3929d5c1eb5706cbe1b116e762ff3e0deca8b715d14bf6ec17"}, 761 | {file = "tornado-6.3.3-cp38-abi3-win32.whl", hash = "sha256:65ceca9500383fbdf33a98c0087cb975b2ef3bfb874cb35b8de8740cf7f41bd3"}, 762 | {file = "tornado-6.3.3-cp38-abi3-win_amd64.whl", hash = "sha256:22d3c2fa10b5793da13c807e6fc38ff49a4f6e1e3868b0a6f4164768bb8e20f5"}, 763 | {file = "tornado-6.3.3.tar.gz", hash = "sha256:e7d8db41c0181c80d76c982aacc442c0783a2c54d6400fe028954201a2e032fe"}, 764 | ] 765 | 766 | [[package]] 767 | name = "tox" 768 | version = "3.28.0" 769 | description = "tox is a generic virtualenv management and test command line tool" 770 | optional = false 771 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 772 | files = [ 773 | {file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"}, 774 | {file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"}, 775 | ] 776 | 777 | [package.dependencies] 778 | colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} 779 | filelock = ">=3.0.0" 780 | packaging = ">=14" 781 | pluggy = ">=0.12.0" 782 | py = ">=1.4.17" 783 | six = ">=1.14.0" 784 | tomli = {version = ">=2.0.1", markers = "python_version >= \"3.7\" and python_version < \"3.11\""} 785 | virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" 786 | 787 | [package.extras] 788 | docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] 789 | testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "psutil (>=5.6.1)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)"] 790 | 791 | [[package]] 792 | name = "tqdm" 793 | version = "4.66.1" 794 | description = "Fast, Extensible Progress Meter" 795 | optional = false 796 | python-versions = ">=3.7" 797 | files = [ 798 | {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, 799 | {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, 800 | ] 801 | 802 | [package.dependencies] 803 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 804 | 805 | [package.extras] 806 | dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] 807 | notebook = ["ipywidgets (>=6)"] 808 | slack = ["slack-sdk"] 809 | telegram = ["requests"] 810 | 811 | [[package]] 812 | name = "typing-extensions" 813 | version = "4.7.1" 814 | description = "Backported and Experimental Type Hints for Python 3.7+" 815 | optional = false 816 | python-versions = ">=3.7" 817 | files = [ 818 | {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, 819 | {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, 820 | ] 821 | 822 | [[package]] 823 | name = "tzdata" 824 | version = "2023.3" 825 | description = "Provider of IANA time zone data" 826 | optional = false 827 | python-versions = ">=2" 828 | files = [ 829 | {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, 830 | {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, 831 | ] 832 | 833 | [[package]] 834 | name = "urllib3" 835 | version = "1.26.15" 836 | description = "HTTP library with thread-safe connection pooling, file post, and more." 837 | optional = false 838 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 839 | files = [ 840 | {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, 841 | {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, 842 | ] 843 | 844 | [package.extras] 845 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] 846 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] 847 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 848 | 849 | [[package]] 850 | name = "virtualenv" 851 | version = "20.24.4" 852 | description = "Virtual Python Environment builder" 853 | optional = false 854 | python-versions = ">=3.7" 855 | files = [ 856 | {file = "virtualenv-20.24.4-py3-none-any.whl", hash = "sha256:29c70bb9b88510f6414ac3e55c8b413a1f96239b6b789ca123437d5e892190cb"}, 857 | {file = "virtualenv-20.24.4.tar.gz", hash = "sha256:772b05bfda7ed3b8ecd16021ca9716273ad9f4467c801f27e83ac73430246dca"}, 858 | ] 859 | 860 | [package.dependencies] 861 | distlib = ">=0.3.7,<1" 862 | filelock = ">=3.12.2,<4" 863 | platformdirs = ">=3.9.1,<4" 864 | 865 | [package.extras] 866 | docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] 867 | test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] 868 | 869 | [[package]] 870 | name = "xyzservices" 871 | version = "2023.7.0" 872 | description = "Source of XYZ tiles providers" 873 | optional = false 874 | python-versions = ">=3.8" 875 | files = [ 876 | {file = "xyzservices-2023.7.0-py3-none-any.whl", hash = "sha256:88e9cbf22b31a2f9c1b242e2b18690f5c705f0e539c9bfd37a10399e1037731b"}, 877 | {file = "xyzservices-2023.7.0.tar.gz", hash = "sha256:0ec928742227d6f5d4367ea7b457fcfed943429f4de2949b5b02a82cdf5569d6"}, 878 | ] 879 | 880 | [[package]] 881 | name = "zipp" 882 | version = "3.16.2" 883 | description = "Backport of pathlib-compatible object wrapper for zip files" 884 | optional = false 885 | python-versions = ">=3.8" 886 | files = [ 887 | {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, 888 | {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, 889 | ] 890 | 891 | [package.extras] 892 | docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] 893 | testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] 894 | 895 | [metadata] 896 | lock-version = "2.0" 897 | python-versions = "^3.9" 898 | content-hash = "691fd9dd0d8140d50db15c522d53ea26f271f375f892ea7fe84b37d2b1dbd304" 899 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "soydata" 3 | version = "0.2.0" 4 | description = "Synthetic dataset" 5 | authors = ["lovit"] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.9" 9 | importlib-metadata = "6.7.0" 10 | tqdm = "^4.65.0" 11 | numpy = "^1.25" 12 | # scipy = "^1.10" 13 | urllib3 = "1.26.15" 14 | bokeh = "^3.0" 15 | plotly = "4.3.0" 16 | 17 | [tool.poetry.dev-dependencies] 18 | flake8 = "6.0.0" 19 | mypy = "1.4.1" 20 | black = "^23.3.0" 21 | tox = "3.28.0" 22 | 23 | [tool.black] 24 | target-version = ['py39'] 25 | line-length = 127 26 | 27 | [build-system] 28 | requires = ["poetry-core>=1.0.0"] 29 | build-backend = "poetry.core.masonry.api" 30 | -------------------------------------------------------------------------------- /soydata/__init__.py: -------------------------------------------------------------------------------- 1 | from . import data 2 | from . import visualize 3 | -------------------------------------------------------------------------------- /soydata/data/__init__.py: -------------------------------------------------------------------------------- 1 | from . import classification 2 | from . import clustering 3 | from . import external 4 | from . import regression 5 | 6 | from .base import make_rectangular 7 | from .base import make_triangular 8 | from .base import make_radial 9 | from .base import rotate 10 | -------------------------------------------------------------------------------- /soydata/data/base.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def check_range(value_1, value_2): 5 | return min(value_1, value_2), max(value_1, value_2) 6 | 7 | 8 | def make_circle(n_samples=100, center_x=0.0, center_y=0.0, r_max=0.5, equal_density=False, seed=None): 9 | """ 10 | Arguments 11 | --------- 12 | n_samples : int 13 | center_x : float 14 | X coordinate of center 15 | center_y : float 16 | Y coordinate of center 17 | r_max : float 18 | Maximum radius 19 | equal_density : Boolean 20 | If True, the density in the cluster is equal. 21 | Else, the closer to center, the denser. 22 | seed : int or None 23 | Random seed 24 | 25 | Returns 26 | ------- 27 | X : numpy.ndarray 28 | The generated samples, shape = (n_samples, 2) 29 | """ 30 | 31 | np.random.seed(seed) 32 | t = np.random.random_sample(n_samples) * 2 * np.pi 33 | r = np.random.random_sample(n_samples) 34 | if equal_density: 35 | r = np.sqrt(r) 36 | r *= r_max 37 | x = np.cos(t) * r + center_x 38 | y = np.sin(t) * r + center_y 39 | X = np.vstack([x, y]).T 40 | return X 41 | 42 | 43 | def make_rectangular(n_samples=100, x_min=0, x_max=1, y_min=0, y_max=1, seed=None): 44 | """ 45 | Arguments 46 | --------- 47 | n_samples : int 48 | x_min : float 49 | Available minimum value of x in rectangular 50 | x_max : float 51 | Available maximum value of x in rectangular 52 | y_min : float 53 | Available minimum value of y in rectangular 54 | y_max : float 55 | Available maximum value of y in rectangular 56 | seed : int or None 57 | Random seed 58 | 59 | Returns 60 | ------- 61 | X : numpy.ndarray 62 | The generated samples, shape = (n_samples, 2) 63 | """ 64 | 65 | np.random.seed(None) 66 | x_min, x_max = check_range(x_min, x_max) 67 | y_min, y_max = check_range(y_min, y_max) 68 | 69 | X = np.random.random_sample((n_samples, 2)) 70 | X[:, 0] = x_min + X[:, 0] * (x_max - x_min) 71 | X[:, 1] = y_min + X[:, 1] * (y_max - y_min) 72 | return X 73 | 74 | 75 | def make_triangular(n_samples=100, upper=True, positive_direction=True, x_min=0, x_max=2, y_min=0, y_max=1, seed=None): 76 | """ 77 | Arguments 78 | --------- 79 | n_samples : int 80 | upper : Boolean 81 | If True, it generated points located in the upper triangle. 82 | positive_direction : Boolean 83 | If True, the slope of triangular is (y_max - y_min) / (x_max - x_min) 84 | Else, the slope is (y_min - y_max) / (x_max - x_min) 85 | x_min : float 86 | Available minimum value of x in triangular 87 | x_max : float 88 | Available maximum value of x in triangular 89 | y_min : float 90 | Available minimum value of y in triangular 91 | y_max : float 92 | Available maximum value of y in triangular 93 | seed : int or None 94 | Random seed 95 | 96 | Returns 97 | ------- 98 | X : numpy.ndarray 99 | The generated samples, shape = (n_samples, 2) 100 | """ 101 | 102 | np.random.seed(None) 103 | grad = (y_max - y_min) / (x_max - x_min) 104 | if positive_direction: 105 | is_upper = lambda q: q[1] - y_min > grad * (q[0] - x_min) 106 | else: 107 | is_upper = lambda q: (q[1] - y_min) < -grad * (q[0] - x_max) 108 | 109 | X = make_rectangular(int(2.5 * n_samples), x_min, x_max, y_min, y_max, seed) 110 | 111 | indices = np.where(np.apply_along_axis(is_upper, 1, X) == upper) 112 | return X[indices][:n_samples] 113 | 114 | 115 | def make_radial( 116 | n_samples_per_cluster=100, 117 | n_classes=2, 118 | n_clusters_per_class=3, 119 | gap=0.0, 120 | equal_proportion=True, 121 | radius_min=0.1, 122 | radius_scale=1.0, 123 | radius_variance=0.0, 124 | seed=None, 125 | ): 126 | """ 127 | Arguments 128 | --------- 129 | n_samples_per_cluster : int (default=100) 130 | The number of points of a class. 131 | n_classes : int (default=2) 132 | The number of spiral 133 | n_clusters_per_class : int (default=3) 134 | The number of clusters of each class 135 | gap : float (default=0.0) 136 | The gap between adjacent clusters 137 | It should be bounded in [0, 1) 138 | equal_proportion : Boolean (default=True) 139 | Equal maximum radius for each cluster 140 | radius_min : float (default=0.1) 141 | Minimum radius of a point 142 | radius_scale : float (default=1.0) 143 | Average radius of points in a cluster 144 | radius_variance : float (default=0.0) 145 | Variance in maximum radius of clusters 146 | seed : int or None 147 | Random seed 148 | 149 | Returns 150 | ------- 151 | X : numpy.ndarray 152 | The generated samples, shape = (n_samples, 2) 153 | labels : numpy.ndarray 154 | The integer labels for class membership of each sample. 155 | Shape = (n_samples,) 156 | """ 157 | 158 | np.random.seed(seed) 159 | 160 | assert 0 <= gap < 1 161 | 162 | if equal_proportion: 163 | theta = 2 * np.pi * np.linspace(0, 1, n_classes * n_clusters_per_class + 1) 164 | else: 165 | theta = np.cumsum(np.linspace(0, 1, n_classes * n_clusters_per_class + 1)) 166 | theta = 2 * np.pi * (theta - theta[0]) / (theta[-1] - theta[0]) 167 | 168 | radius = radius_scale * (1 + radius_variance * np.random.rand(n_clusters_per_class * n_classes).reshape(-1)) 169 | 170 | X = [] 171 | labels = [] 172 | 173 | # for each cluster 174 | for s in range(n_clusters_per_class * n_classes): 175 | t_begin = theta[s] 176 | t_end = theta[s + 1] 177 | if gap > 0: 178 | t_begin += (t_end - t_begin) * gap 179 | t_end -= (t_end - t_begin) * gap 180 | t = t_begin + (t_end - t_begin) * np.random.rand(1, n_samples_per_cluster) 181 | r = np.diag(radius_min + radius[s] * (np.random.rand(1, n_samples_per_cluster) ** (1 / 2))[0]) 182 | x = np.cos(t) 183 | y = np.sin(t) 184 | Xs = np.concatenate((x, y)) 185 | Xs = Xs.dot(r) 186 | Xs = Xs.T 187 | 188 | label = np.asarray([s % n_classes] * n_samples_per_cluster) 189 | X.append(Xs) 190 | labels.append(label) 191 | 192 | X = np.concatenate(X) 193 | labels = np.concatenate(labels) 194 | 195 | return X, labels 196 | 197 | 198 | def generate_range(scale): 199 | base = np.random.random_sample(1) * 0.5 200 | ranges = np.random.random_sample(3) * scale 201 | ranges.sort() 202 | min = ranges[0] + base 203 | max = ranges[-1] + base 204 | return min, max 205 | 206 | 207 | def rotate(xy, radians): 208 | """ 209 | Arguments 210 | --------- 211 | xy : numpy.ndarray 212 | Shape = (n_data, 2) 213 | radians : float 214 | Radian to rotate 215 | 216 | Returns 217 | ------- 218 | xy : numpy.ndarray 219 | Rotated 2d array, shape = (n_data, 2) 220 | """ 221 | x = xy[:, 0] 222 | y = xy[:, 1] 223 | xx = x * np.cos(radians) + y * np.sin(radians) 224 | yy = -x * np.sin(radians) + y * np.cos(radians) 225 | xy = np.vstack([xx, yy]).T 226 | return xy 227 | -------------------------------------------------------------------------------- /soydata/data/classification/__init__.py: -------------------------------------------------------------------------------- 1 | from .manifold import make_moons 2 | from .manifold import make_spiral 3 | from .recipe import make_predefined_data 4 | from .spatial import make_two_layer_radial 5 | from .spatial import make_complex_rectangulars 6 | from .spatial import make_multilayer_rectangulars 7 | -------------------------------------------------------------------------------- /soydata/data/classification/manifold.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def make_moons(n_samples=100, xy_ratio=1.0, x_gap=0.0, y_gap=0.0, noise=None, seed=None): 5 | """ 6 | Arguments 7 | ---------- 8 | n_samples : int (default=100) 9 | The total number of points generated. 10 | xy_ratio : float (default=1.0) 11 | ratio of y range over x range. It should be positive. 12 | x_gap : float (default=0.0) 13 | Gap between y-axis center of two moons. 14 | It should be larger than -0.3 15 | y_gap : float (default=0.0) 16 | Gap between x-axis center of two moons. 17 | It should be larger than -0.3 18 | noise : float or None (default=None) 19 | Standard deviation of Gaussian noise added to the data. 20 | seed : int or None 21 | Random seed 22 | 23 | Returns 24 | ------- 25 | X : numpy.ndarray 26 | The generated samples, shape = (n_samples, 2) 27 | labels : numpy.ndarray 28 | The integer labels (0 or 1) for class membership of each sample. 29 | Shape = (n_samples,) 30 | 31 | Usage 32 | ----- 33 | >>> from soydata.data.classification import make_moons 34 | >>> from soydata.visualize import scatterplot 35 | 36 | >>> X, labels = make_moons(n_samples=1000, noise=0.1) 37 | >>> scatterplot(X, labels=labels) 38 | """ 39 | 40 | assert xy_ratio > 0 41 | assert -0.3 <= x_gap 42 | assert -0.3 <= y_gap 43 | 44 | n_samples_out = n_samples // 2 45 | n_samples_in = n_samples - n_samples_out 46 | 47 | np.random.seed(seed) 48 | 49 | outer_circ_x = np.cos(np.linspace(0, np.pi, n_samples_out)) - x_gap 50 | outer_circ_y = xy_ratio * np.sin(np.linspace(0, np.pi, n_samples_out)) + y_gap 51 | inner_circ_x = 1 - np.cos(np.linspace(0, np.pi, n_samples_in)) + x_gap 52 | inner_circ_y = xy_ratio * (1 - np.sin(np.linspace(0, np.pi, n_samples_in)) - (0.5 + y_gap)) 53 | 54 | X = np.vstack((np.append(outer_circ_x, inner_circ_x), np.append(outer_circ_y, inner_circ_y))).T 55 | labels = np.hstack([np.zeros(n_samples_out, dtype=np.intp), np.ones(n_samples_in, dtype=np.intp)]) 56 | 57 | if noise is not None: 58 | noise = np.random.normal(scale=noise, size=X.shape) 59 | noise[:, 1] = noise[:, 1] * xy_ratio 60 | X += noise 61 | 62 | return X, labels 63 | 64 | 65 | def make_spiral( 66 | n_samples_per_class=300, 67 | n_classes=2, 68 | n_rotations=3, 69 | gap_between_spiral=0.0, 70 | gap_between_start_point=0.0, 71 | equal_interval=True, 72 | noise=None, 73 | seed=None, 74 | ): 75 | """ 76 | Arguments 77 | --------- 78 | n_samples_per_class : int (default=300) 79 | The number of points of a class. 80 | n_classes : int (default=2) 81 | The number of spiral 82 | n_rotations : int (default=3) 83 | The rotation number of spiral 84 | gap_between_spiral : float (default=0.0) 85 | The gap between two parallel lines 86 | gap_betweein_start_point : float (default=0.0) 87 | The gap between spiral origin points 88 | equal_interval : Boolean (default=True) 89 | Equal interval on a spiral line if True. 90 | Else their intervals are proportional to their radius. 91 | noise : double or None (default=None) 92 | Standard deviation of Gaussian noise added to the data. 93 | seed : int or None 94 | Random seed 95 | 96 | Returns 97 | ------- 98 | X : numpy.ndarray 99 | The generated samples, shape = (n_samples, 2) 100 | labels : numpy.ndarray 101 | The integer labels for class membership of each sample. 102 | Shape = (n_samples,) 103 | 104 | Usage 105 | ----- 106 | >>> from soydata.data.classification import make_spiral 107 | >>> from soydata.visualize import scatterplot 108 | 109 | >>> X, labels = make_spiral(noise=0.5, n_rotations=2) 110 | >>> scatterplot(X, labels=labels) 111 | """ 112 | 113 | assert 1 <= n_classes and type(n_classes) == int 114 | 115 | np.random.seed(seed) 116 | 117 | X = [] 118 | theta = 2 * np.pi * np.linspace(0, 1, n_classes + 1)[:n_classes] 119 | 120 | for c in range(n_classes): 121 | t_shift = theta[c] 122 | x_shift = gap_between_start_point * np.cos(t_shift) 123 | y_shift = gap_between_start_point * np.sin(t_shift) 124 | 125 | power = 0.5 if equal_interval else 1.0 126 | t = n_rotations * np.pi * (2 * np.random.rand(1, n_samples_per_class) ** (power)) 127 | x = (1 + gap_between_spiral) * t * np.cos(t + t_shift) + x_shift 128 | y = (1 + gap_between_spiral) * t * np.sin(t + t_shift) + y_shift 129 | Xc = np.concatenate((x, y)) 130 | 131 | if noise is not None: 132 | Xc += np.random.normal(scale=noise, size=Xc.shape) 133 | 134 | Xc = Xc.T 135 | X.append(Xc) 136 | 137 | X = np.concatenate(X) 138 | labels = np.asarray([c for c in range(n_classes) for _ in range(n_samples_per_class)]) 139 | 140 | return X, labels 141 | -------------------------------------------------------------------------------- /soydata/data/classification/recipe.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from ..base import make_rectangular 4 | from ..base import make_triangular 5 | 6 | 7 | def make_predefined_data(name="decision-tree-1", n_samples=1000): 8 | """ 9 | Arguments 10 | --------- 11 | name : str 12 | Dataset name, Valid values are following 13 | 14 | names = ['decision-tree-1', 'decision-tree-2'] 15 | 16 | n_samples : int 17 | Number of generated samples 18 | 19 | Returns 20 | ------- 21 | X : numpy.ndarray 22 | The generated samples, shape = (n_samples, 2) 23 | labels : numpy.ndarray 24 | The integer labels for class membership of each sample. 25 | Shape = (n_samples,) 26 | 27 | Usage 28 | ----- 29 | >>> from soydata.data.classification import make_decision_tree_data_from_recipe 30 | >>> from soydata.visualize import scatterplot 31 | 32 | >>> X, labels = make_predefined_data('decision-tree-1', n_samples=5000) 33 | >>> X, labels = make_predefined_data('decision-tree-2', n_samples=5000) 34 | >>> p = scatterplot(X, labels=labels) 35 | """ 36 | if name == "decision-tree-1": 37 | recipe = [ 38 | # (type, volume, label, x_min, x_max, y_min, y_max) 39 | ("rec", 25, 1, 0, 5, 0, 5), 40 | ("rec", 15, 0, 5, 10, 0, 3), 41 | ("rec", 3, 0, 5, 7, 3, 4.5), 42 | ("rec", 10, 1, 7, 10, 3, 6.5), 43 | ("rec", 1, 1, 5, 7, 4.5, 5), 44 | ("rec", 10, 1, 2, 7, 5, 7), 45 | ("rec", 4, 0, 0, 2, 5, 7), 46 | ("rec", 13.5, 0, 0, 4.5, 7, 10), 47 | ("rec", 8.5, 1, 4.5, 7, 7, 10), 48 | ("rec", 10, 0, 7, 10, 6.5, 10), 49 | ] 50 | return make_decision_tree_data_from_recipe(n_samples, recipe) 51 | elif name == "decision-tree-2": 52 | # (type, volume, label, x_min, x_max, y_min, y_max) 53 | recipe = [ 54 | ("rec", 32, 1, 0, 7, 0, 4), 55 | ("rec", 9.5, 0, 7, 10, 0, 3.5), 56 | ("rec", 4.5, 1, 7, 10, 3.5, 5), 57 | ("rec", 0.5, 1, 7.5, 8, 4, 5), 58 | ("rec", 7.5, 0, 7.5, 10, 5, 8), 59 | ("rec", 4.5, 1, 8, 10, 8, 10), 60 | ("rec", 1, 0, 7.5, 8, 8, 10), 61 | ("rec", 16.5, 0, 2, 7.5, 7, 10), 62 | ("rec", 12, 0, 0, 2, 4, 10), 63 | ("upper", 8.25, 1, 2, 7.5, 4, 7), 64 | ("lower", 8.25, 0, 2, 7.5, 4, 7), 65 | ] 66 | return make_decision_tree_data_from_recipe(n_samples, recipe) 67 | else: 68 | raise ValueError("Unknown datataset") 69 | 70 | 71 | def make_decision_tree_data_from_recipe(n_samples, recipe): 72 | """ 73 | Arguments 74 | --------- 75 | n_samples : int 76 | Number of generated samples 77 | recipe : list of tuple 78 | (type, volume, label, x_min, x_max, y_min, y_max) form 79 | Available types are following 80 | 81 | types = ['rec', 'upper', 'lower'] 82 | 83 | Returns 84 | ------- 85 | X : numpy.ndarray 86 | The generated samples, shape = (n_samples, 2) 87 | labels : numpy.ndarray 88 | The integer labels for class membership of each sample. 89 | Shape = (n_samples,) 90 | 91 | Usage 92 | ----- 93 | >>> recipe = [ 94 | # (type, volume, label, x_min, x_max, y_min, y_max) 95 | ('rec', 25, 1, 0, 5, 0, 5), 96 | ('rec', 15, 0, 5, 10, 0, 3), 97 | ('rec', 3, 0, 5, 7, 3, 4.5), 98 | ('rec', 10, 1, 7, 10, 3, 6.5), 99 | ('rec', 1, 1, 5, 7, 4.5, 5), 100 | ('rec', 10, 1, 2, 7, 5, 7), 101 | ('rec', 4, 0, 0, 2, 5, 7), 102 | ('rec', 13.5, 0, 0, 4.5, 7, 10), 103 | ('rec', 8.5, 1, 4.5, 7, 7, 10), 104 | ('rec', 10, 0, 7, 10, 6.5, 10), 105 | ] 106 | >>> n_samples = 1000 107 | >>> make_decision_tree_data_from_recipe(n_samples, recipe) 108 | """ 109 | labels = [] 110 | X = [] 111 | for type, volume, label, x_min, x_max, y_min, y_max in recipe: 112 | ns = int(n_samples * volume / 100) 113 | if type == "rec": 114 | Xs = make_rectangular(ns, x_min, x_max, y_min, y_max) 115 | elif type == "upper": 116 | Xs = make_triangular(ns, upper=True, x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max) 117 | elif type == "lower": 118 | Xs = make_triangular(ns, upper=False, x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max) 119 | else: 120 | raise ValueError("Profile type error. Type={}".format(p[0])) 121 | X.append(Xs) 122 | labels += [label] * ns 123 | X = np.vstack(X)[:n_samples] 124 | labels = np.asarray(labels, dtype=np.int32)[:n_samples] 125 | return X, labels 126 | -------------------------------------------------------------------------------- /soydata/data/classification/spatial.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..base import make_radial 3 | from ..base import make_rectangular 4 | from ..base import generate_range 5 | from ..base import rotate 6 | 7 | 8 | def make_two_layer_radial( 9 | n_samples_per_cluster=100, n_classes=2, n_clusters_per_class=3, gap=0.0, equal_proportion=True, seed=None 10 | ): 11 | """ 12 | Arguments 13 | ---------- 14 | n_samples_per_class : int, optional (default=100) 15 | The number of points of a class. 16 | n_classes : int, optional (default=2) 17 | The number of spiral 18 | n_clusters_per_class : int, optional (default=3) 19 | The number of clusters of each class 20 | gap : float, optional (default=0.0) 21 | The gap between adjacent clusters 22 | It should be bounded in [0, 1) 23 | equal_proportion : Boolean, optional (default=True) 24 | Equal maximum radius for each section 25 | seed : int or None 26 | Random seed 27 | 28 | Returns 29 | ------- 30 | X : numpy.ndarray 31 | The generated samples, shape = (n_samples, 2) 32 | labels : numpy.ndarray 33 | The integer labels [0, 1, ..., n_classes) for class membership of each sample. 34 | Shape = (n_samples,) 35 | 36 | Usage 37 | ----- 38 | >>> from soydata.data.classification import make_two_layer_radial 39 | >>> from soydata.visualize import scatterplot 40 | 41 | >>> X, labels = make_two_layer_radial() 42 | >>> scatterplot(X, labels=labels) 43 | """ 44 | np.random.seed(seed) 45 | 46 | X_0, labels_0 = make_radial( 47 | n_samples_per_cluster, n_classes, n_clusters_per_class, gap, equal_proportion, radius_min=0.1, radius_scale=1 48 | ) 49 | X_1, labels_1 = make_radial( 50 | n_samples_per_cluster, n_classes, n_clusters_per_class, gap, equal_proportion, radius_min=1 * (1 + gap), radius_scale=1 51 | ) 52 | 53 | labels_1[:-n_samples_per_cluster] = labels_1[n_samples_per_cluster:] 54 | labels_1[-n_samples_per_cluster:] = 0 55 | 56 | X = np.concatenate((X_0, X_1)) 57 | labels = np.concatenate((labels_0, labels_1)) 58 | return X, labels 59 | 60 | 61 | def make_complex_rectangulars(n_samples=3000, n_classes=2, volume=0.5, n_rectangulars=10, seed=None): 62 | """ 63 | Arguments 64 | --------- 65 | n_samples : int 66 | The number of generated sample data in 2D [(0, 1), (0, 1)] 67 | n_classes : int 68 | The number of rectangular classes 69 | volume : float 70 | The volume of randomly generated rectangulars 71 | n_rectangulars : int 72 | The number of randomly generated rectangulars 73 | seed : int or None 74 | Random seed 75 | 76 | Returns 77 | ------- 78 | X : numpy.ndarray 79 | The generated samples, shape = (n_samples, 2) 80 | labels : numpy.ndarray 81 | The integer labels for class membership of each sample. 82 | Shape = (n_samples,) 83 | 84 | Usage 85 | ----- 86 | >>> from soydata.data.classification import make_complex_rectangulars 87 | >>> from soydata.visualize import scatterplot 88 | 89 | >>> X, labels = make_complex_rectangulars(n_samples=5000, n_rectangulars=20, volume=0.5, seed=0) 90 | >>> p = scatterplot(X, labels=labels) 91 | """ 92 | 93 | np.random.seed(seed) 94 | X = np.random.random_sample((n_samples, 2)) 95 | labels = np.zeros(n_samples) 96 | for label in range(n_rectangulars): 97 | x_min, x_max = generate_range(volume) 98 | y_min, y_max = generate_range(volume) 99 | indices = np.where((x_min <= X[:, 0]) & (X[:, 0] <= x_max) & (y_min <= X[:, 1]) & (X[:, 1] <= y_max))[0] 100 | label = label % n_classes 101 | labels[indices] = label 102 | return X, labels 103 | 104 | 105 | def make_multilayer_rectangulars(rec_size=100, n_layers=2, n_classes=2, random_label=False, rotate_radian=0, seed=None): 106 | """ 107 | Arguments 108 | --------- 109 | rec_size : int 110 | The number of samples in a rectangular 111 | n_layers : int 112 | The number of layers. The number of rectauglars is (2 * `n_layers`)^2 113 | n_classes : int 114 | The number of classes. It is used only when `random_label` is True 115 | random_label : Boolean 116 | If True, it permutate labels 117 | rotate_radian : float 118 | If rotate_radian != 0, it rotates X 119 | seed : int or None 120 | Random seed 121 | 122 | Returns 123 | ------- 124 | X : numpy.ndarray 125 | The generated samples, shape = (n_samples, 2) 126 | labels : numpy.ndarray 127 | The integer labels [0, 0, ..., 1, 1, ... 0, 0, ...] 128 | 129 | Usage 130 | ----- 131 | Import functions 132 | 133 | >>> from soydata.data.classification import make_multilayer_rectangulars 134 | >>> from soydata.visualize import scatterplot 135 | 136 | To generate regular patterned data 137 | 138 | >>> X, labels = make_multilayer_rectangulars(rec_size=100, n_layers=2) 139 | >>> p = scatterplot(X, labels=labels, title='Multilayer rectangulars') 140 | 141 | To generate random labeled data 142 | 143 | >>> X, labels = make_multilayer_rectangulars( 144 | n_layers=5, random_label=True, n_classes=5) 145 | >>> p = scatterplot(X, labels=labels, title='Random-labeled multilayer rectangulars') 146 | """ 147 | np.random.seed(seed) 148 | n_rectangulars = (2 * n_layers) ** 2 149 | X, labels = [], [] 150 | for y in range(-n_layers, n_layers, 1): 151 | for x in range(-n_layers, n_layers, 1): 152 | X.append(make_rectangular(n_samples=rec_size, x_min=x, x_max=x + 1, y_min=y, y_max=y + 1)) 153 | if random_label: 154 | label = np.random.randint(0, n_classes) 155 | else: 156 | label = abs(y % 2 + x) % 2 157 | labels += [label] * rec_size 158 | X = np.vstack(X) 159 | if abs(rotate_radian) > 0: 160 | X = rotate(X, rotate_radian) 161 | return X, labels 162 | -------------------------------------------------------------------------------- /soydata/data/clustering/__init__.py: -------------------------------------------------------------------------------- 1 | from .clustering import make_circular_clusters 2 | from .clustering import make_rectangular_clusters 3 | from .manifold import make_swiss_roll 4 | -------------------------------------------------------------------------------- /soydata/data/clustering/clustering.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from ..base import check_range 3 | from ..base import make_circle 4 | 5 | 6 | def make_circular_clusters( 7 | n_clusters=8, size_min=100, size_max=120, r_min=0.1, r_max=0.2, equal_density=False, noise=0.0, centers=None, seed=None 8 | ): 9 | """ 10 | Arguments 11 | --------- 12 | n_clusters : int 13 | Number of clusters 14 | size_min : int 15 | Minimum number of samples in a cluster 16 | size_max : int 17 | Maximum number of samples in a cluster 18 | r_min : float 19 | Minimum radius of clusters 20 | r_max : float 21 | Maximum radius of clusters 22 | equal_density : Boolean 23 | If True, the density in the cluster is equal. 24 | Else, the closer to center, the denser. 25 | noise : float 26 | Proportion of noise and cluster data 27 | centers : list of tuple or None 28 | User-specified center of clusters 29 | seed : int or None 30 | Random seed 31 | 32 | Returns 33 | ------- 34 | X : numpy.ndarray 35 | Samples = (n_samples, dim) 36 | labels : numpy.ndarray 37 | The integer labels for class membership of each sample. 38 | Shape = (n_samples,) 39 | 40 | Usage 41 | ----- 42 | >>> from soydata.data.clustering import make_circular_clusters 43 | >>> from soydata.visualize import scatterplot 44 | 45 | >>> X, labels = X, labels = make_circular_clusters(n_clusters=10, 46 | r_min=0.05, r_max=0.1, equal_density=True, noise=0.05, seed=0) 47 | >>> scatterplot(X, labels=labels) 48 | """ 49 | 50 | np.random.seed(seed) 51 | r_min, r_max = check_range(r_min, r_max) 52 | 53 | if hasattr(r_max, "__len__"): 54 | if len(r_max) < n_clsuters: 55 | raise ValueError("Set `r_max` with number or same length of list") 56 | radius = r_max[:n_clusters] 57 | else: 58 | radius = np.random.random_sample(n_clusters) * (r_max - r_min) + r_min 59 | 60 | if hasattr(centers, "__len__"): 61 | if len(r_max) < n_clsuters: 62 | raise ValueError("Set `centers` with None or same length of list") 63 | centers = np.asarray(centers[:n_clusters]) 64 | else: 65 | centers = np.random.random_sample((n_clusters, 2)) 66 | if centers.shape[1] != 2: 67 | raise ValueError("The dimension of center must be 2") 68 | 69 | sizes = np.random.randint(low=size_min, high=size_max, size=(n_clusters,)) 70 | 71 | X = [] 72 | for size, center, r in zip(sizes, centers, radius): 73 | Xi = make_circle(size, center[0], center[1], r, equal_density) 74 | X.append(Xi) 75 | labels = [i for i, Xi in enumerate(X) for _ in range(Xi.shape[0])] 76 | 77 | X = np.vstack(X) 78 | labels = np.asarray(labels, dtype=np.int32) 79 | 80 | if noise > 0: 81 | n_noise = int(X.shape[0] * noise) 82 | factor_x = 1.1 * (X[:, 0].max() - X[:, 0].min()) 83 | factor_y = 1.1 * (X[:, 1].max() - X[:, 1].min()) 84 | noise = np.random.random_sample((n_noise, 2)) 85 | noise[:, 0] = noise[:, 0] * factor_x 86 | noise[:, 1] = noise[:, 1] * factor_y 87 | X = np.vstack([X, noise]) 88 | labels = np.concatenate([labels, -np.ones(n_noise, dtype=np.int32)]) 89 | return X, labels 90 | 91 | 92 | def make_rectangular_clusters(n_clusters=8, dim=2, size_min=10, size_max=15, volume=0.2, seed=None): 93 | """ 94 | Arguments 95 | --------- 96 | n_clusters : int 97 | Number of clusters 98 | dim : int 99 | Dimension of data 100 | size_min : int 101 | Minimum number of samples in a cluster 102 | size_max : int 103 | Maximum number of samples in a cluster 104 | volume : float 105 | The volume of a cluster 106 | seed : int or None 107 | Random seed 108 | 109 | Returns 110 | ------- 111 | X : numpy.ndarray 112 | Samples = (n_samples, dim) 113 | labels : numpy.ndarray 114 | The integer labels for class membership of each sample. 115 | Shape = (n_samples,) 116 | 117 | Usage 118 | ----- 119 | >>> X, labels = make_rectangular_clusters(n_clusters=8, size_min=10, size_max=15, volume=0.2, seed=0) 120 | """ 121 | np.random.seed(seed) 122 | X = [] 123 | labels = [] 124 | for label in range(n_clusters): 125 | size = np.random.randint(size_min, size_max + 1, 1)[0] 126 | center = np.random.random_sample((1, dim)) 127 | samples = center + volume * (np.random.random_sample((size, dim)) - 0.5) 128 | X.append(samples) 129 | labels += [label] * size 130 | X = np.vstack(X) 131 | labels = np.asarray(labels, dtype=np.int32) 132 | return X, labels 133 | -------------------------------------------------------------------------------- /soydata/data/clustering/manifold.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def make_swiss_roll(n_samples=100, n_rotations=1.5, gap=0, thickness=0.0, width=10.0, discretize=True, seed=None): 5 | """ 6 | Arguments 7 | --------- 8 | n_samples : int (default=100) 9 | The number of samples in swiss roll 10 | n_rotations : float (default=1.5) 11 | The number of turns 12 | gap : float (default=1.0) 13 | The gap between adjacent roll-planes 14 | thickness : float (default=0.0) 15 | The thickness of roll plane 16 | width : float (default=0.0) 17 | The scale of y axis 18 | descretize : Boolean 19 | If True, it returns color as integer which is bounded in [0, 256) 20 | 21 | Returns 22 | ------- 23 | X : numpy.ndarray 24 | Shape = (n_samples, 3) 25 | color : numpy.ndarray 26 | Shape = (n_samples,) 27 | The normalized univariate position of the sample according to the main 28 | dimension of the points in the manifold. Its scale is bounded in [0, 1] 29 | """ 30 | np.random.seed(seed) 31 | 32 | t = n_rotations * np.pi * (1 + 2 * np.random.rand(1, n_samples)) 33 | x = (1 + gap) * t * np.cos(t) 34 | y = width * (np.random.rand(1, n_samples) - 0.5) 35 | z = (1 + gap) * t * np.sin(t) 36 | 37 | X = np.concatenate((x, y, z)) 38 | X += thickness * np.random.randn(3, n_samples) 39 | X = X.T 40 | t = np.squeeze(t) 41 | color = (t - t.min()) / (t.max() - t.min()) 42 | 43 | if discretize: 44 | color = np.asarray([int(256 * c) for c in color], dtype=np.int32) 45 | 46 | return X, color 47 | -------------------------------------------------------------------------------- /soydata/data/external/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovit/synthetic_dataset/c2103e830617455363d7fc734e911212a86dbe8f/soydata/data/external/__init__.py -------------------------------------------------------------------------------- /soydata/data/external/movielens/.gitignore: -------------------------------------------------------------------------------- 1 | ml-20m/ 2 | ml-latest-small/ 3 | 4 | -------------------------------------------------------------------------------- /soydata/data/external/movielens/__init__.py: -------------------------------------------------------------------------------- 1 | from .io import download_movielens 2 | from .io import load_rating 3 | -------------------------------------------------------------------------------- /soydata/data/external/movielens/io.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | from scipy.sparse import csr_matrix 4 | 5 | from ..utils import download_a_file 6 | from ..utils import external_path 7 | from ..utils import unzip 8 | 9 | 10 | movielens_20m_url = "http://files.grouplens.org/datasets/movielens/ml-20m.zip" 11 | movielens_20m_readme_url = "http://files.grouplens.org/datasets/movielens/ml-20m-README.html" 12 | movielens_small_url = "http://files.grouplens.org/datasets/movielens/ml-latest-small.zip" 13 | movielens_small_readme_url = "http://files.grouplens.org/datasets/movielens/ml-latest-small-README.html" 14 | 15 | movielens_20m_dir = f"{external_path}/movielens/ml-20m/" 16 | movielens_small_dir = f"{external_path}/movielens/ml-latest-small/" 17 | 18 | 19 | def download_movielens(size="20m", force=False): 20 | """ 21 | Arguments 22 | --------- 23 | size : str 24 | Datasize. one of ['20m', 'small'] 25 | force : Boolean 26 | If True, it overwrites data if the file exists 27 | """ 28 | 29 | data_url, readme_url, dirname = check_size(size) 30 | download(data_url, readme_url, dirname, force) 31 | 32 | 33 | def download(data_url, readme_url, dirname, force=False): 34 | if os.path.exists(dirname) and (not force): 35 | answer = input("The data already is downloaded. Re-download it? [yes|no]").lower().strip() 36 | if answer != "yes": 37 | print("Terminated") 38 | return None 39 | 40 | notice(readme_url) 41 | 42 | filename = data_url.split("/")[-1] 43 | zippath = f"{external_path}/movielens/{filename}" 44 | if download_a_file(data_url, zippath): 45 | print("downloaded") 46 | if unzip(zippath, f"{external_path}/movielens/"): 47 | print("unzip the downloaded file") 48 | if os.path.exists(zippath): 49 | os.remove(zippath) 50 | 51 | 52 | def notice(readme_url): 53 | print( 54 | "This function downloads MovieLens data from GroupLens\n" 55 | f"Please read first {readme_url}\n" 56 | "All permissions are in GroupLens, and this function is an external utility" 57 | " to conventiently use MovieLens data.\n" 58 | ) 59 | 60 | 61 | def check_size(size): 62 | if not size in ["20m", "small"]: 63 | raise ValueError("`size` must be one of ['20m', 'small']") 64 | 65 | if size == "20m": 66 | data_url = movielens_20m_url 67 | readme_url = movielens_20m_readme_url 68 | dirname = movielens_20m_dir 69 | else: 70 | data_url = movielens_small_url 71 | readme_url = movielens_small_readme_url 72 | dirname = movielens_small_dir 73 | return data_url, readme_url, dirname 74 | 75 | 76 | def load_rating(size="20m"): 77 | """ 78 | Arguments 79 | --------- 80 | size : str 81 | Datasize. one of ['20m', 'small'] 82 | 83 | Returns 84 | ------- 85 | user_item : scipy.sparse.csr_matrix 86 | (user, item) = rate 87 | timestamps : numpy.ndarray 88 | UNIX time format datetime 89 | """ 90 | data_url, readme_url, dirname = check_size(size) 91 | if not os.path.exists(dirname): 92 | print("The data has not been downloaded, Download it first.\n") 93 | download(data_url, readme_url, dirname) 94 | else: 95 | notice(readme_url) 96 | 97 | rating_path = f"{dirname}/ratings.csv" 98 | 99 | users = [] 100 | items = [] 101 | ratings = [] 102 | timestamps = [] 103 | 104 | with open(rating_path, encoding="utf-8") as f: 105 | next(f) 106 | for line in f: 107 | u, i, r, t = line.strip().split(",") 108 | users.append(int(u)) 109 | items.append(int(i)) 110 | ratings.append(float(r)) 111 | timestamps.append(int(t)) 112 | 113 | user_item = csr_matrix((ratings, (users, items))) 114 | timestamps = np.array(timestamps) 115 | return user_item, timestamps 116 | -------------------------------------------------------------------------------- /soydata/data/external/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import zipfile 4 | 5 | 6 | external_path = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | 9 | def download_a_file(url, fname): 10 | """ 11 | Arguments 12 | -------- 13 | url : str 14 | URL address of file to be downloaded 15 | fname : str 16 | Download file address 17 | Returns 18 | ------- 19 | flag : Boolean 20 | It return True if downloading success else return False 21 | """ 22 | 23 | fname = os.path.abspath(fname) 24 | dirname = os.path.dirname(fname) 25 | if not os.path.exists(dirname): 26 | os.makedirs(dirname) 27 | 28 | # If you do not set user-agent, downloading from url is stalled. 29 | headers = {"user-agent": "Wget/1.16 (linux-gnu)"} 30 | 31 | try: 32 | r = requests.get(url, stream=True, headers=headers) 33 | with open(fname, "wb") as f: 34 | for chunk in r.iter_content(chunk_size=1024): 35 | if chunk: 36 | f.write(chunk) 37 | return True 38 | except Exception as e: 39 | print(e) 40 | return False 41 | 42 | 43 | def unzip(source, destination): 44 | """ 45 | Arguments 46 | --------- 47 | source : str 48 | zip file address. It doesn't matter absolute path or relative path 49 | destination : 50 | Directory path of unzip 51 | Returns 52 | ------- 53 | flag : Boolean 54 | It return True if downloading success else return False 55 | """ 56 | 57 | abspath = os.path.abspath(destination) 58 | dirname = os.path.dirname(abspath) 59 | if not os.path.exists(dirname): 60 | os.makedirs(dirname) 61 | 62 | try: 63 | downloaded = zipfile.ZipFile(source) 64 | downloaded.extractall(destination) 65 | return True 66 | except Exception as e: 67 | print(e) 68 | return False 69 | -------------------------------------------------------------------------------- /soydata/data/regression/__init__.py: -------------------------------------------------------------------------------- 1 | from .simple import make_linear_regression_data 2 | from .simple import make_polynomial_regression_data 3 | from .simple import make_randomwalk_timeseries_data 4 | from .simple import make_stepwise_regression_data 5 | from .simple import make_step_function_data 6 | -------------------------------------------------------------------------------- /soydata/data/regression/simple.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def make_linear_regression_data(n_samples=100, a=1.0, b=1.0, noise=1.0, x_range=(-10.0, 10.0), seed=None): 5 | """ 6 | It generates artificial data for linear regression 7 | 8 | Arguments 9 | --------- 10 | n_samples : int 11 | Number of generated data 12 | a : float 13 | Regression coefficient a in 'y = ax + b' 14 | b : float 15 | Interpret coefficient b in 'y = ax + b' 16 | noise : float 17 | Range of residual, e = y - (ax + b) 18 | x_range : tuple 19 | size = (float, float) 20 | seed : int or None 21 | Random seed 22 | 23 | Returns 24 | ------- 25 | x : numpy.ndarray 26 | Input data sequence, shape = (n_data,) 27 | y : numpy.ndarray 28 | Output data sequence with random noise, shape = (n_data,) 29 | y_true : numpy.ndarray 30 | Truen output data sequence (regressed output), shape = (n_data,) 31 | 32 | Usage 33 | ----- 34 | >>> from soydata.data.regression import make_linear_regression_data 35 | >>> from soydata.visualize import lineplot 36 | 37 | >>> x, y, _ = make_linear_regression_data() 38 | >>> x, y, y_true = make_linear_regression_data( 39 | n_data=100, a=1.0, b=1.0, noise=1.0, x_range=(-10.0, 10.0)) 40 | 41 | >>> p = lineplot(x, y, show_inline=False, line_width=2) 42 | 43 | To overlay true regression line 44 | 45 | >>> p = lineplot(x, y_true, p=p, line_color='red') 46 | """ 47 | 48 | assert (len(x_range) == 2) and (x_range[0] < x_range[1]) 49 | 50 | if isinstance(seed, int): 51 | np.random.seed(seed) 52 | 53 | x_scale = x_range[1] - x_range[0] 54 | x = np.random.random_sample(n_samples) * x_scale + x_range[0] 55 | residual = (np.random.random_sample(n_samples) - 0.5) * noise 56 | y = a * x + b + residual 57 | y_true = a * x + b 58 | 59 | return x, y, y_true 60 | 61 | 62 | def make_polynomial_regression_data(n_samples=100, degree=2, coefficients=None, noise=0.1, x_range=(-1.0, 1.0), seed=None): 63 | """ 64 | It generates artificial data for linear regression 65 | 66 | Arguments 67 | --------- 68 | n_samples : int 69 | Number of generated data 70 | degree : int 71 | Degree of polynomial 72 | coefficients : list_or_None 73 | Coefficients bi such that y = b0 + sum_{i=1 to degree} bi x x^i 74 | noise : float 75 | Range of residual, e = y - f(x) 76 | x_range : tuple 77 | size = (float, float) 78 | seed : int or None 79 | Random seed 80 | 81 | Returns 82 | ------- 83 | x : numpy.ndarray 84 | Input data sequence, shape = (n_data,) 85 | y : numpy.ndarray 86 | Output data sequence with random noise, shape = (n_data,) 87 | y_true : numpy.ndarray 88 | Truen output data sequence (regressed output), shape = (n_data,) 89 | 90 | Usage 91 | ----- 92 | >>> from soydata.data.regression import make_linear_regression_data 93 | >>> from soydata.visualize import lineplot 94 | 95 | >>> x, y, y_true = make_polynomial_regression_data(degree=5, noise=0.2, seed=1) 96 | >>> p = lineplot(x, y, show_inline=False, line_width=2) 97 | 98 | To overlay true regression line 99 | 100 | >>> p = lineplot(x, y_true, p=p, line_color='red') 101 | """ 102 | 103 | if (not isinstance(degree, int)) or (degree < 0): 104 | raise ValueError(f"degree must be nonnegative integer, however input is {degree}") 105 | 106 | if isinstance(seed, int): 107 | np.random.seed(seed) 108 | 109 | if coefficients is None: 110 | sign = np.random.randint(2, size=degree + 1) * 2 - 1 111 | coefficients = np.random.random_sample(degree + 1) + 0.5 112 | coefficients *= sign 113 | 114 | len_coef = len(coefficients) 115 | if len_coef != degree + 1: 116 | raise ValueError("The length of coefficients must be degree" f"However, length is {len_coef} with degree = {degree}") 117 | 118 | x_scale = x_range[1] - x_range[0] 119 | x = np.random.random_sample(n_samples) * x_scale + x_range[0] 120 | 121 | y_true = np.zeros(n_samples) 122 | for p, coef in enumerate(coefficients): 123 | y_true = y_true + coef * np.power(x, p) 124 | residual = (np.random.random_sample(n_samples) - 0.5) * noise 125 | y = y_true + residual 126 | 127 | return x, y, y_true 128 | 129 | 130 | def make_randomwalk_timeseries_data(n_samples=500, std=1.0, noise=1.0, n_repeats=1, seed=None): 131 | """ 132 | It generated timeseries formed regression dataset. 133 | 134 | y_t = y_(t-1) + N(0, std) 135 | 136 | Arguments 137 | --------- 138 | n_samples : int 139 | Number of generated data 140 | std : float 141 | Standard devation of N(0, std) 142 | noise : float 143 | Factor of noise 144 | n_repeats : int 145 | Number of samples which have same x 146 | x_range : tuple 147 | size = (float, float) 148 | seed : int or None 149 | Random seed 150 | 151 | Returns 152 | ------- 153 | >>> from soydata.data.regression import make_randomwalk_timeseries 154 | >>> from soydata.visualize import scatterplot 155 | 156 | >>> x, y, y_true = make_randomwalk_timeseries_data(n_repeats=3, noise=0.1, std=10, seed=0) 157 | >>> scatterplot(x, y, size=3, height=200) 158 | """ 159 | 160 | np.random.seed(seed) 161 | x_line = np.arange(n_samples) 162 | y_line = (np.random.randn(n_samples) * std).cumsum() 163 | x = np.concatenate([x_line for _ in range(n_repeats)]) 164 | add_noise = lambda y: y + np.random.randn(n_samples) * std * noise 165 | y = np.concatenate([add_noise(y_line) for _ in range(n_repeats)]) 166 | return x, y, y_line 167 | 168 | 169 | def make_stepwise_regression_data(n_samples=500, n_steps=5, noise=0.1, x_range=(-1, 1), seed=None): 170 | """ 171 | It generated timeseries formed regression dataset. 172 | 173 | y_t = y_(t-1) + N(0, std) 174 | 175 | Arguments 176 | --------- 177 | n_samples : int 178 | Number of generated data 179 | n_steps : int 180 | Number of partially linear regions 181 | noise : float 182 | Noise level 183 | x_range : tuple 184 | size = (float, float) 185 | seed : int or None 186 | Random seed 187 | 188 | Returns 189 | ------- 190 | >>> from soydata.data.regression import make_stepwise_regression_data 191 | >>> from soydata.visualize import scatterplot 192 | 193 | >>> x, y, y_true = make_stepwise_regression_data(n_steps=5, noise=0.1, seed=5) 194 | >>> p = scatterplot(x, y, size=3, height=400, width=800, title='Stepwise regression') 195 | """ 196 | 197 | np.random.seed(seed) 198 | x = np.linspace(x_range[0], x_range[1], n_samples) 199 | a = 5 * (np.random.random_sample(n_steps) - 0.5) 200 | size = n_samples / (n_steps * 3) + np.random.random_sample(n_steps) * n_samples / n_steps 201 | size = np.array(n_samples * size / size.sum(), dtype=np.int32) 202 | size = np.concatenate([[0], size]).cumsum() 203 | size[-1] = n_samples 204 | y_last = 0 205 | y_line = [] 206 | for slope, b, e in zip(a, size, size[1:]): 207 | y_partial = (x[b:e] - x[b]) * slope + y_last 208 | y_last = y_partial[-1] 209 | y_line.append(y_partial) 210 | y_line = np.concatenate(y_line) 211 | y = y_line + np.random.randn(n_samples) * noise 212 | return x, y, y_line 213 | 214 | 215 | def make_step_function_data(n_samples=500, n_steps=5, noise=0.1, x_range=(-1, 1), seed=None): 216 | """ 217 | It generated timeseries formed regression dataset. 218 | 219 | y_t = y_(t-1) + N(0, std) 220 | 221 | Arguments 222 | --------- 223 | n_samples : int 224 | Number of generated data 225 | n_steps : int 226 | Number of partially linear regions 227 | noise : float 228 | Noise level 229 | x_range : tuple 230 | size = (float, float) 231 | seed : int or None 232 | Random seed 233 | 234 | Returns 235 | ------- 236 | >>> from soydata.data.regression import make_step_function_data 237 | >>> from soydata.visualize import scatterplot 238 | 239 | >>> x, y, y_true = make_step_function_data(n_steps=5, noise=0.1, seed=5) 240 | >>> p = scatterplot(x, y, size=3, height=400, width=800, title='Step function data') 241 | """ 242 | 243 | np.random.seed(seed) 244 | x = np.linspace(x_range[0], x_range[1], n_samples) 245 | y_mean = 5 * (np.random.random_sample(n_steps) - 0.5) 246 | size = n_samples / (n_steps * 3) + np.random.random_sample(n_steps) * n_samples / n_steps 247 | size = np.array(n_samples * size / size.sum(), dtype=np.int32) 248 | size = np.concatenate([[0], size]).cumsum() 249 | size[-1] = n_samples 250 | y_line = [] 251 | for mean, b, e in zip(y_mean, size, size[1:]): 252 | y_line.append([mean] * (e - b)) 253 | y_line = np.concatenate(y_line) 254 | y = y_line + np.random.randn(n_samples) * noise 255 | return x, y, y_line 256 | -------------------------------------------------------------------------------- /soydata/visualize/__init__.py: -------------------------------------------------------------------------------- 1 | from .bokeh import scatterplot 2 | from .bokeh import lineplot 3 | # from .plotly import scatterplot3d 4 | from .utils import use_notebook 5 | -------------------------------------------------------------------------------- /soydata/visualize/bokeh.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from bokeh.plotting import figure, show 3 | from bokeh.palettes import Spectral, Turbo256 4 | 5 | 6 | def scatterplot( 7 | x, y=None, labels=None, color="#5e4fa2", size=5, alpha=0.95, p=None, show_inline=True, marker="circle", **kargs 8 | ): 9 | if isinstance(x, np.ndarray) and (len(x.shape) == 2) and (x.shape[1] == 2): 10 | if (y is not None) and (labels is None): 11 | labels = y 12 | x, y = x[:, 0], x[:, 1] 13 | 14 | if p is None: 15 | p = initialize_figure( 16 | title=kargs.get("title", None), 17 | height=kargs.get("height", 600), 18 | width=kargs.get("width", 600), 19 | toolbar_location=kargs.get("toolbar_location", "right"), 20 | tools=kargs.get("tools", "default"), 21 | ) 22 | 23 | if labels is not None: 24 | color = initialize_palette(labels=labels, palette=kargs.get("palette", None), n_labels=kargs.get("n_labels", -1))[ 25 | : x.shape[0] 26 | ] 27 | 28 | p.scatter(x, y, color=color, size=size, alpha=alpha, marker=marker) 29 | if show_inline: 30 | show(p) 31 | 32 | return p 33 | 34 | 35 | def lineplot(X, y=None, pairs=None, line_width=0.5, line_dash=(5, 3), line_color="#2b83ba", p=None, show_inline=True, **kargs): 36 | if p is None: 37 | p = initialize_figure( 38 | title=kargs.get("title", None), 39 | height=kargs.get("height", 600), 40 | width=kargs.get("width", 600), 41 | toolbar_location=kargs.get("toolbar_location", "right"), 42 | tools=kargs.get("tools", "default"), 43 | ) 44 | 45 | if y is not None: 46 | X = np.vstack([X, y]).T 47 | if line_dash is None: 48 | line_dash = [] 49 | 50 | if pairs is not None: 51 | for f, t in pairs: 52 | x = [X[f, 0], X[t, 0]] 53 | y = [X[f, 1], X[t, 1]] 54 | p.line(x, y, line_color=line_color, line_dash=line_dash, line_width=line_width) 55 | else: 56 | X.sort(axis=0) 57 | x = X[:, 0] 58 | y = X[:, 1] 59 | p.line(x, y, line_color=line_color, line_dash=line_dash, line_width=line_width) 60 | 61 | if show_inline: 62 | show(p) 63 | 64 | return p 65 | 66 | 67 | def initialize_figure(title=None, height=600, width=600, toolbar_location="right", tools="default"): 68 | if tools == "default": 69 | tools = "pan wheel_zoom box_zoom save reset".split() 70 | return figure(title=title, height=height, width=width, toolbar_location=toolbar_location, tools=tools) 71 | 72 | 73 | def initialize_palette(labels, palette=None, n_labels=-1): 74 | uniques = np.unique(labels) 75 | uniques = uniques[np.where(uniques >= 0)[0]] 76 | if n_labels < 1: 77 | n_labels = uniques.max() + 1 78 | if palette is not None: 79 | palette = palette 80 | elif n_labels <= 3: 81 | palette = "#B8D992 #BE83AB #78CCD0".split() 82 | elif n_labels <= 11: 83 | palette = Spectral[max(4, n_labels)] 84 | else: 85 | step = int(256 / n_labels) 86 | palette = [Turbo256[i] for i in range(0, 256, step)][:n_labels] 87 | n_colors = len(palette) 88 | label_to_color = {label: palette[i % n_colors] for i, label in enumerate(uniques)} 89 | label_to_color[-1] = "lightgrey" 90 | color = [label_to_color[label] for label in labels] 91 | return color 92 | -------------------------------------------------------------------------------- /soydata/visualize/plotly.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from plotly.offline import plot, iplot 3 | import plotly.graph_objs as go 4 | 5 | 6 | def scatterplot3d(X, color, text=None, title=None, width=600, height=600, marker_size=3, colorscale="Jet", show_inline=True): 7 | """ 8 | Arguments 9 | --------- 10 | X : numpy.ndarray 11 | Sample data, Shape = (n_samples, 3) 12 | color : numpy.ndarray 13 | Shape = (n_samples,) 14 | The normalized univariate position of the sample according to the main 15 | dimension of the points in the manifold. 16 | Its scale is bounded in [0, 1] with float or [0, 256) with integer. 17 | text : str or None 18 | Description of each point 19 | title : str or None 20 | Title of the figure 21 | width : int 22 | Figure width, default is 600 23 | height : int 24 | Figure height, default is 600 25 | marker_size : int 26 | Size of markers 27 | colorscale : str 28 | Predefined colorscales in Plotly express, for example `Jet`, `Magma` 29 | show_inline : Boolean 30 | If True, it shows the figure 31 | 32 | Returns 33 | ------- 34 | fig : plotly.graph_objs._figure.Figure 35 | Plotly figure 36 | 37 | Usage 38 | ----- 39 | To draw 3D scatterplot of swiss-roll 40 | 41 | >>> from soydata.data.unsupervised import make_swiss_roll 42 | >>> from soydata.visualize import scatterplot3d 43 | 44 | >>> X, color = make_swiss_roll(n_samples=1000, thickness=1.5, gap=2) 45 | >>> fig = scatterplot3d(X, color) 46 | 47 | To save figure 48 | 49 | >>> from plotly.offline import plot 50 | >>> plot(fig, filename='plotly-3d-scatter-small.html', auto_open=False) 51 | 52 | """ 53 | data = go.Scatter3d( 54 | x=X[:, 0], 55 | y=X[:, 1], 56 | z=X[:, 2], 57 | text=text if text else ["point #{}".format(i) for i in range(X.shape[0])], 58 | mode="markers", 59 | marker=dict( 60 | size=marker_size, 61 | color=color, 62 | colorscale=colorscale, 63 | line=dict( 64 | # color='rgba(217, 217, 217, 0.14)', 65 | # color='rgb(217, 217, 217)', 66 | width=0.0 67 | ), 68 | opacity=0.8, 69 | ), 70 | ) 71 | 72 | layout = go.Layout( 73 | title=title if title else "", 74 | autosize=False, 75 | width=width, 76 | height=height, 77 | margin=go.Margin(l=50, r=50, b=100, t=100, pad=4), 78 | # paper_bgcolor='#7f7f7f', 79 | # plot_bgcolor='#c7c7c7' 80 | ) 81 | 82 | fig = go.Figure(data=[data], layout=layout) 83 | if show_inline: 84 | iplot(fig) 85 | 86 | return fig 87 | -------------------------------------------------------------------------------- /soydata/visualize/utils.py: -------------------------------------------------------------------------------- 1 | from bokeh.plotting import output_notebook 2 | from plotly.offline import init_notebook_mode 3 | 4 | 5 | def use_notebook(): 6 | init_notebook_mode(connected=True) 7 | output_notebook() 8 | --------------------------------------------------------------------------------