voronoiq 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
voronoiq-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include README.md
2
+ include LICENSE
3
+ recursive-include voronoiq *.py
4
+ recursive-include tests *.py
@@ -0,0 +1,228 @@
1
+ Metadata-Version: 2.4
2
+ Name: voronoiq
3
+ Version: 0.1.0
4
+ Summary: Weighted Voronoi Diagrams — multiplicative, additive and power (Laguerre) modes
5
+ Author-email: Emerson Marreiros <ec2763@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/emerson-marreiros/voronoiq
8
+ Project-URL: Repository, https://github.com/emerson-marreiros/voronoiq
9
+ Project-URL: Issues, https://github.com/emerson-marreiros/voronoiq/issues
10
+ Keywords: voronoi,weighted voronoi,computational geometry,diagram,laguerre
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Topic :: Scientific/Engineering :: Visualization
18
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy>=1.23
23
+ Requires-Dist: matplotlib>=3.5
24
+ Provides-Extra: full
25
+ Requires-Dist: scipy>=1.9; extra == "full"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: scipy>=1.9; extra == "dev"
29
+ Requires-Dist: build; extra == "dev"
30
+ Requires-Dist: twine; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # voronoiq — Weighted Voronoi Diagrams for Python
34
+
35
+ A lightweight, dependency-light Python library for constructing and
36
+ visualising **weighted Voronoi diagrams**, including:
37
+
38
+ | Mode | Distance function | Effect of larger weight |
39
+ |---|---|---|
40
+ | `"multiplicative"` | `dist(p,g) / w(g)` | larger region |
41
+ | `"additive"` | `dist(p,g) − w(g)` | larger region |
42
+ | `"power"` | `dist(p,g)² − w(g)²` | larger region (power diagram) |
43
+
44
+ ---
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ pip install numpy scipy matplotlib
50
+ # clone / copy voronoiq/ into your project
51
+ ```
52
+
53
+ Dependencies: **numpy**, **scipy** (optional, for boundary_pixels),
54
+ **matplotlib** (for visualisation).
55
+
56
+ ---
57
+
58
+ ## Quick start
59
+
60
+ ```python
61
+ import numpy as np
62
+ from voronoiq import WeightedVoronoi
63
+
64
+ pts = np.array([[0.2, 0.3],
65
+ [0.7, 0.6],
66
+ [0.5, 0.1],
67
+ [0.1, 0.9]])
68
+ w = np.array([1.0, 2.5, 0.5, 1.8])
69
+
70
+ wv = WeightedVoronoi(pts, w, mode="multiplicative", resolution=512)
71
+ wv.compute()
72
+ wv.plot() # shows an interactive matplotlib figure
73
+ wv.to_png("out.png")
74
+ ```
75
+
76
+ ---
77
+
78
+ ## API reference
79
+
80
+ ### `WeightedVoronoi(points, weights, **kwargs)`
81
+
82
+ | Parameter | Default | Description |
83
+ |---|---|---|
84
+ | `points` | — | `(N, 2)` generator coordinates |
85
+ | `weights` | — | `(N,)` generator weights |
86
+ | `mode` | `"multiplicative"` | distance metric |
87
+ | `resolution` | `512` | pixels along longer axis |
88
+ | `domain` | auto (bounding box + 5 %) | `((xmin,xmax),(ymin,ymax))` |
89
+ | `palette` | `"tab20"` | matplotlib colormap name |
90
+ | `show_generators` | `True` | draw seed points |
91
+ | `show_weights` | `False` | annotate weights |
92
+ | `show_boundaries` | `True` | draw cell edges |
93
+
94
+ #### Methods
95
+
96
+ ```python
97
+ wv.compute() # rasterise the diagram (required first)
98
+
99
+ wv.plot(**kwargs) # returns (fig, ax)
100
+ wv.plot_distance_field() # heat-map of min weighted distance
101
+ wv.plot_comparison() # side-by-side of all 3 modes
102
+
103
+ wv.owner(x, y) # generator index owning (x, y)
104
+ wv.region_of(x, y) # VoronoiRegion containing (x, y)
105
+ wv.nearest_generators(x, y, k=3) # k nearest generators by weighted dist
106
+
107
+ wv.to_png("out.png", dpi=150)
108
+ wv.to_svg("out.svg")
109
+ wv.to_csv("out.csv") # index, x, y, weight, area, centroid
110
+ wv.to_label_array() # (H, W) int ndarray — copy
111
+ ```
112
+
113
+ #### Key attributes (after `compute()`)
114
+
115
+ | Attribute | Type | Description |
116
+ |---|---|---|
117
+ | `label_grid` | `(H, W) int32` | generator index per pixel |
118
+ | `dist_grid` | `(H, W) float64` | minimum weighted distance per pixel |
119
+ | `regions` | `list[VoronoiRegion]` | one object per generator |
120
+
121
+ ---
122
+
123
+ ### `VoronoiRegion`
124
+
125
+ ```python
126
+ r = wv.regions[0]
127
+
128
+ r.index # int — generator index
129
+ r.generator # (2,) float — (x, y)
130
+ r.weight # float
131
+ r.pixel_mask # (H, W) bool
132
+ r.color # (R, G, B) tuple
133
+
134
+ r.area # int — number of pixels
135
+ r.centroid # (2,) float — mean (x, y) of mask pixels
136
+ r.boundary_pixels # (K, 2) row/col indices of boundary pixels
137
+ ```
138
+
139
+ ---
140
+
141
+ ### `voronoiq.generators`
142
+
143
+ ```python
144
+ from voronoiq.generators import (
145
+ random_generators, # uniform random
146
+ grid_generators, # regular grid with optional jitter
147
+ poisson_disk_generators, # Bridson blue-noise sampling
148
+ )
149
+
150
+ pts, w = random_generators(n=20, weight_range=(0.5, 2.0), seed=42)
151
+ pts, w = grid_generators(nx=6, ny=6, jitter=0.04, seed=0)
152
+ pts, w = poisson_disk_generators(min_dist=0.1, seed=7)
153
+ ```
154
+
155
+ All functions return `(points, weights)` tuples ready for
156
+ `WeightedVoronoi`.
157
+
158
+ ---
159
+
160
+ ### `voronoiq.metrics`
161
+
162
+ ```python
163
+ from voronoiq.metrics import (
164
+ multiplicative_weighted_distance, # scalar
165
+ additive_weighted_distance,
166
+ power_distance,
167
+ batch_multiplicative, # vectorised over generators
168
+ batch_additive,
169
+ batch_power,
170
+ )
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Examples
176
+
177
+ ### Comparison of all three modes
178
+
179
+ ```python
180
+ wv = WeightedVoronoi(pts, w, mode="multiplicative", resolution=400)
181
+ wv.compute()
182
+ fig, axes = wv.plot_comparison(figsize=(18, 6))
183
+ ```
184
+
185
+ ### Distance field heat-map
186
+
187
+ ```python
188
+ wv.plot_distance_field(cmap="plasma")
189
+ ```
190
+
191
+ ### Querying which region owns a point
192
+
193
+ ```python
194
+ idx = wv.owner(0.5, 0.5)
195
+ region = wv.region_of(0.5, 0.5)
196
+ print(region)
197
+ # VoronoiRegion(index=1, generator=(0.700, 0.600), weight=2.500, area=14832 px)
198
+ ```
199
+
200
+ ### Exporting
201
+
202
+ ```python
203
+ wv.to_png("voronoi.png", dpi=200)
204
+ wv.to_svg("voronoi.svg")
205
+ wv.to_csv("voronoi.csv")
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Project structure
211
+
212
+ ```
213
+ voronoiq/
214
+ ├── __init__.py # public API
215
+ ├── diagram.py # WeightedVoronoi class
216
+ ├── region.py # VoronoiRegion dataclass
217
+ ├── generators.py # random / grid / Poisson-disk seed generators
218
+ └── metrics.py # distance functions + registry
219
+ tests/
220
+ └── test_voronoiq.py # full test suite (pytest)
221
+ README.md
222
+ ```
223
+
224
+ ---
225
+
226
+ ## License
227
+
228
+ MIT
@@ -0,0 +1,196 @@
1
+ # voronoiq — Weighted Voronoi Diagrams for Python
2
+
3
+ A lightweight, dependency-light Python library for constructing and
4
+ visualising **weighted Voronoi diagrams**, including:
5
+
6
+ | Mode | Distance function | Effect of larger weight |
7
+ |---|---|---|
8
+ | `"multiplicative"` | `dist(p,g) / w(g)` | larger region |
9
+ | `"additive"` | `dist(p,g) − w(g)` | larger region |
10
+ | `"power"` | `dist(p,g)² − w(g)²` | larger region (power diagram) |
11
+
12
+ ---
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install numpy scipy matplotlib
18
+ # clone / copy voronoiq/ into your project
19
+ ```
20
+
21
+ Dependencies: **numpy**, **scipy** (optional, for boundary_pixels),
22
+ **matplotlib** (for visualisation).
23
+
24
+ ---
25
+
26
+ ## Quick start
27
+
28
+ ```python
29
+ import numpy as np
30
+ from voronoiq import WeightedVoronoi
31
+
32
+ pts = np.array([[0.2, 0.3],
33
+ [0.7, 0.6],
34
+ [0.5, 0.1],
35
+ [0.1, 0.9]])
36
+ w = np.array([1.0, 2.5, 0.5, 1.8])
37
+
38
+ wv = WeightedVoronoi(pts, w, mode="multiplicative", resolution=512)
39
+ wv.compute()
40
+ wv.plot() # shows an interactive matplotlib figure
41
+ wv.to_png("out.png")
42
+ ```
43
+
44
+ ---
45
+
46
+ ## API reference
47
+
48
+ ### `WeightedVoronoi(points, weights, **kwargs)`
49
+
50
+ | Parameter | Default | Description |
51
+ |---|---|---|
52
+ | `points` | — | `(N, 2)` generator coordinates |
53
+ | `weights` | — | `(N,)` generator weights |
54
+ | `mode` | `"multiplicative"` | distance metric |
55
+ | `resolution` | `512` | pixels along longer axis |
56
+ | `domain` | auto (bounding box + 5 %) | `((xmin,xmax),(ymin,ymax))` |
57
+ | `palette` | `"tab20"` | matplotlib colormap name |
58
+ | `show_generators` | `True` | draw seed points |
59
+ | `show_weights` | `False` | annotate weights |
60
+ | `show_boundaries` | `True` | draw cell edges |
61
+
62
+ #### Methods
63
+
64
+ ```python
65
+ wv.compute() # rasterise the diagram (required first)
66
+
67
+ wv.plot(**kwargs) # returns (fig, ax)
68
+ wv.plot_distance_field() # heat-map of min weighted distance
69
+ wv.plot_comparison() # side-by-side of all 3 modes
70
+
71
+ wv.owner(x, y) # generator index owning (x, y)
72
+ wv.region_of(x, y) # VoronoiRegion containing (x, y)
73
+ wv.nearest_generators(x, y, k=3) # k nearest generators by weighted dist
74
+
75
+ wv.to_png("out.png", dpi=150)
76
+ wv.to_svg("out.svg")
77
+ wv.to_csv("out.csv") # index, x, y, weight, area, centroid
78
+ wv.to_label_array() # (H, W) int ndarray — copy
79
+ ```
80
+
81
+ #### Key attributes (after `compute()`)
82
+
83
+ | Attribute | Type | Description |
84
+ |---|---|---|
85
+ | `label_grid` | `(H, W) int32` | generator index per pixel |
86
+ | `dist_grid` | `(H, W) float64` | minimum weighted distance per pixel |
87
+ | `regions` | `list[VoronoiRegion]` | one object per generator |
88
+
89
+ ---
90
+
91
+ ### `VoronoiRegion`
92
+
93
+ ```python
94
+ r = wv.regions[0]
95
+
96
+ r.index # int — generator index
97
+ r.generator # (2,) float — (x, y)
98
+ r.weight # float
99
+ r.pixel_mask # (H, W) bool
100
+ r.color # (R, G, B) tuple
101
+
102
+ r.area # int — number of pixels
103
+ r.centroid # (2,) float — mean (x, y) of mask pixels
104
+ r.boundary_pixels # (K, 2) row/col indices of boundary pixels
105
+ ```
106
+
107
+ ---
108
+
109
+ ### `voronoiq.generators`
110
+
111
+ ```python
112
+ from voronoiq.generators import (
113
+ random_generators, # uniform random
114
+ grid_generators, # regular grid with optional jitter
115
+ poisson_disk_generators, # Bridson blue-noise sampling
116
+ )
117
+
118
+ pts, w = random_generators(n=20, weight_range=(0.5, 2.0), seed=42)
119
+ pts, w = grid_generators(nx=6, ny=6, jitter=0.04, seed=0)
120
+ pts, w = poisson_disk_generators(min_dist=0.1, seed=7)
121
+ ```
122
+
123
+ All functions return `(points, weights)` tuples ready for
124
+ `WeightedVoronoi`.
125
+
126
+ ---
127
+
128
+ ### `voronoiq.metrics`
129
+
130
+ ```python
131
+ from voronoiq.metrics import (
132
+ multiplicative_weighted_distance, # scalar
133
+ additive_weighted_distance,
134
+ power_distance,
135
+ batch_multiplicative, # vectorised over generators
136
+ batch_additive,
137
+ batch_power,
138
+ )
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Examples
144
+
145
+ ### Comparison of all three modes
146
+
147
+ ```python
148
+ wv = WeightedVoronoi(pts, w, mode="multiplicative", resolution=400)
149
+ wv.compute()
150
+ fig, axes = wv.plot_comparison(figsize=(18, 6))
151
+ ```
152
+
153
+ ### Distance field heat-map
154
+
155
+ ```python
156
+ wv.plot_distance_field(cmap="plasma")
157
+ ```
158
+
159
+ ### Querying which region owns a point
160
+
161
+ ```python
162
+ idx = wv.owner(0.5, 0.5)
163
+ region = wv.region_of(0.5, 0.5)
164
+ print(region)
165
+ # VoronoiRegion(index=1, generator=(0.700, 0.600), weight=2.500, area=14832 px)
166
+ ```
167
+
168
+ ### Exporting
169
+
170
+ ```python
171
+ wv.to_png("voronoi.png", dpi=200)
172
+ wv.to_svg("voronoi.svg")
173
+ wv.to_csv("voronoi.csv")
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Project structure
179
+
180
+ ```
181
+ voronoiq/
182
+ ├── __init__.py # public API
183
+ ├── diagram.py # WeightedVoronoi class
184
+ ├── region.py # VoronoiRegion dataclass
185
+ ├── generators.py # random / grid / Poisson-disk seed generators
186
+ └── metrics.py # distance functions + registry
187
+ tests/
188
+ └── test_voronoiq.py # full test suite (pytest)
189
+ README.md
190
+ ```
191
+
192
+ ---
193
+
194
+ ## License
195
+
196
+ MIT
@@ -0,0 +1,50 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "voronoiq"
7
+ version = "0.1.0"
8
+ description = "Weighted Voronoi Diagrams — multiplicative, additive and power (Laguerre) modes"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [
12
+ { name = "Emerson Marreiros", email = "ec2763@gmail.com" }
13
+ ]
14
+ keywords = ["voronoi", "weighted voronoi", "computational geometry", "diagram", "laguerre"]
15
+ classifiers = [
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Operating System :: OS Independent",
22
+ "Topic :: Scientific/Engineering :: Visualization",
23
+ "Topic :: Scientific/Engineering :: Mathematics",
24
+ ]
25
+ requires-python = ">=3.10"
26
+ dependencies = [
27
+ "numpy>=1.23",
28
+ "matplotlib>=3.5",
29
+ ]
30
+
31
+ [project.optional-dependencies]
32
+ full = ["scipy>=1.9"]
33
+ dev = [
34
+ "pytest>=7.0",
35
+ "scipy>=1.9",
36
+ "build",
37
+ "twine",
38
+ ]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/emerson-marreiros/voronoiq"
42
+ Repository = "https://github.com/emerson-marreiros/voronoiq"
43
+ Issues = "https://github.com/emerson-marreiros/voronoiq/issues"
44
+
45
+ [tool.setuptools.packages.find]
46
+ include = ["voronoiq*"]
47
+
48
+ [tool.pytest.ini_options]
49
+ testpaths = ["tests"]
50
+ env = ["MPLBACKEND=Agg"] # remove esta linha se não instalar pytest-env
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ # tests/conftest.py
2
+ # Force the non-interactive Agg backend before any test imports matplotlib.
3
+ # This avoids TclError / display issues in CI and headless environments.
4
+ import matplotlib
5
+ matplotlib.use("Agg")