├── .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 |
--------------------------------------------------------------------------------