rgrid-python 4.5.3__py3-none-any.whl
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.
- grid_py/__init__.py +340 -0
- grid_py/_arrow.py +331 -0
- grid_py/_clippath.py +170 -0
- grid_py/_colour.py +815 -0
- grid_py/_coords.py +1534 -0
- grid_py/_curve.py +1668 -0
- grid_py/_display_list.py +507 -0
- grid_py/_draw.py +1397 -0
- grid_py/_edit.py +756 -0
- grid_py/_font_metrics.py +319 -0
- grid_py/_gpar.py +572 -0
- grid_py/_grab.py +501 -0
- grid_py/_grob.py +1377 -0
- grid_py/_group.py +798 -0
- grid_py/_highlevel.py +2176 -0
- grid_py/_just.py +361 -0
- grid_py/_layout.py +593 -0
- grid_py/_ls.py +895 -0
- grid_py/_mask.py +196 -0
- grid_py/_path.py +414 -0
- grid_py/_patterns.py +1049 -0
- grid_py/_primitives.py +2198 -0
- grid_py/_renderer_base.py +1184 -0
- grid_py/_scene_graph.py +248 -0
- grid_py/_size.py +1352 -0
- grid_py/_state.py +683 -0
- grid_py/_transforms.py +448 -0
- grid_py/_typeset.py +384 -0
- grid_py/_units.py +1924 -0
- grid_py/_utils.py +310 -0
- grid_py/_viewport.py +1649 -0
- grid_py/_vp_calc.py +970 -0
- grid_py/py.typed +0 -0
- grid_py/renderer.py +1762 -0
- grid_py/renderer_web.py +764 -0
- grid_py/resources/d3.v7.min.js +2 -0
- grid_py/resources/gridpy.css +80 -0
- grid_py/resources/gridpy.js +813 -0
- rgrid_python-4.5.3.dist-info/METADATA +489 -0
- rgrid_python-4.5.3.dist-info/RECORD +42 -0
- rgrid_python-4.5.3.dist-info/WHEEL +4 -0
- rgrid_python-4.5.3.dist-info/licenses/LICENSE +3 -0
grid_py/_transforms.py
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"""Affine transformation matrices for grid_py (port of R's grid group transforms).
|
|
2
|
+
|
|
3
|
+
This module provides functions that construct 3x3 affine transformation
|
|
4
|
+
matrices used by the group/define/use grob system. Each function returns a
|
|
5
|
+
:class:`numpy.ndarray` of shape ``(3, 3)`` and dtype ``float64``.
|
|
6
|
+
|
|
7
|
+
The matrices follow the **row-vector** convention used by R's *grid* package:
|
|
8
|
+
a point ``[x, y, 1]`` is transformed via ``point @ matrix``. Translation
|
|
9
|
+
terms therefore live in the bottom row (indices ``[2, 0]`` and ``[2, 1]``).
|
|
10
|
+
|
|
11
|
+
Group transforms
|
|
12
|
+
----------------
|
|
13
|
+
Low-level building blocks that mirror R's ``groupTranslate``,
|
|
14
|
+
``groupRotate``, ``groupScale``, ``groupShear``, and ``groupFlip``.
|
|
15
|
+
|
|
16
|
+
Definition transforms
|
|
17
|
+
---------------------
|
|
18
|
+
Transforms applied when defining a group (``defineGrob``).
|
|
19
|
+
|
|
20
|
+
Use transforms
|
|
21
|
+
--------------
|
|
22
|
+
Transforms applied when reusing a group (``useGrob``).
|
|
23
|
+
|
|
24
|
+
Viewport transforms
|
|
25
|
+
-------------------
|
|
26
|
+
Combined transforms that map from one viewport to another.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import math
|
|
32
|
+
from typing import Union
|
|
33
|
+
|
|
34
|
+
import numpy as np
|
|
35
|
+
from numpy.typing import NDArray
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
# Group (primitive) transforms
|
|
39
|
+
"group_translate",
|
|
40
|
+
"group_rotate",
|
|
41
|
+
"group_scale",
|
|
42
|
+
"group_shear",
|
|
43
|
+
"group_flip",
|
|
44
|
+
# Definition transforms
|
|
45
|
+
"defn_translate",
|
|
46
|
+
"defn_rotate",
|
|
47
|
+
"defn_scale",
|
|
48
|
+
# Use transforms
|
|
49
|
+
"use_translate",
|
|
50
|
+
"use_rotate",
|
|
51
|
+
"use_scale",
|
|
52
|
+
# Viewport transforms
|
|
53
|
+
"viewport_translate",
|
|
54
|
+
"viewport_rotate",
|
|
55
|
+
"viewport_scale",
|
|
56
|
+
"viewport_transform",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
# ---------------------------------------------------------------------------
|
|
60
|
+
# Type alias
|
|
61
|
+
# ---------------------------------------------------------------------------
|
|
62
|
+
Matrix3x3 = NDArray[np.float64]
|
|
63
|
+
|
|
64
|
+
# ============================================================================
|
|
65
|
+
# Group (primitive) transforms
|
|
66
|
+
# ============================================================================
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def group_translate(dx: float = 0, dy: float = 0) -> Matrix3x3:
|
|
70
|
+
"""Return a 3x3 translation matrix.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
dx : float, optional
|
|
75
|
+
Horizontal translation (default ``0``).
|
|
76
|
+
dy : float, optional
|
|
77
|
+
Vertical translation (default ``0``).
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
numpy.ndarray
|
|
82
|
+
A 3x3 affine translation matrix.
|
|
83
|
+
|
|
84
|
+
Examples
|
|
85
|
+
--------
|
|
86
|
+
>>> group_translate(10, 20)
|
|
87
|
+
array([[ 1., 0., 0.],
|
|
88
|
+
[ 0., 1., 0.],
|
|
89
|
+
[10., 20., 1.]])
|
|
90
|
+
"""
|
|
91
|
+
mat = np.eye(3, dtype=np.float64)
|
|
92
|
+
mat[2, 0] = dx
|
|
93
|
+
mat[2, 1] = dy
|
|
94
|
+
return mat
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def group_rotate(angle: float = 0, device: bool = True) -> Matrix3x3:
|
|
98
|
+
"""Return a 3x3 rotation matrix.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
angle : float, optional
|
|
103
|
+
Rotation angle in **degrees** (default ``0``). Positive values
|
|
104
|
+
rotate counter-clockwise in the standard mathematical sense.
|
|
105
|
+
device : bool, optional
|
|
106
|
+
If ``True`` (default) the rotation follows device conventions
|
|
107
|
+
(identical to R's ``groupRotate`` with ``device=TRUE`` when the
|
|
108
|
+
device origin is at the bottom-left).
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
numpy.ndarray
|
|
113
|
+
A 3x3 affine rotation matrix.
|
|
114
|
+
|
|
115
|
+
Examples
|
|
116
|
+
--------
|
|
117
|
+
>>> import numpy as np
|
|
118
|
+
>>> np.allclose(group_rotate(90) @ np.array([1, 0, 1]),
|
|
119
|
+
... np.array([0, 1, 1]), atol=1e-15)
|
|
120
|
+
True
|
|
121
|
+
"""
|
|
122
|
+
theta = math.radians(angle)
|
|
123
|
+
cos_t = math.cos(theta)
|
|
124
|
+
sin_t = math.sin(theta)
|
|
125
|
+
mat = np.eye(3, dtype=np.float64)
|
|
126
|
+
mat[0, 0] = cos_t
|
|
127
|
+
mat[0, 1] = sin_t
|
|
128
|
+
mat[1, 0] = -sin_t
|
|
129
|
+
mat[1, 1] = cos_t
|
|
130
|
+
return mat
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def group_scale(sx: float = 1, sy: float = 1) -> Matrix3x3:
|
|
134
|
+
"""Return a 3x3 scaling matrix.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
sx : float, optional
|
|
139
|
+
Horizontal scale factor (default ``1``).
|
|
140
|
+
sy : float, optional
|
|
141
|
+
Vertical scale factor (default ``1``).
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
numpy.ndarray
|
|
146
|
+
A 3x3 affine scaling matrix.
|
|
147
|
+
|
|
148
|
+
Examples
|
|
149
|
+
--------
|
|
150
|
+
>>> group_scale(2, 3)
|
|
151
|
+
array([[2., 0., 0.],
|
|
152
|
+
[0., 3., 0.],
|
|
153
|
+
[0., 0., 1.]])
|
|
154
|
+
"""
|
|
155
|
+
mat = np.eye(3, dtype=np.float64)
|
|
156
|
+
mat[0, 0] = sx
|
|
157
|
+
mat[1, 1] = sy
|
|
158
|
+
return mat
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def group_shear(sx: float = 0, sy: float = 0) -> Matrix3x3:
|
|
162
|
+
"""Return a 3x3 shear matrix.
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
sx : float, optional
|
|
167
|
+
Shear factor along the *x*-axis (default ``0``). This is placed
|
|
168
|
+
at matrix position ``[1, 0]``, matching R's ``groupShear``.
|
|
169
|
+
sy : float, optional
|
|
170
|
+
Shear factor along the *y*-axis (default ``0``). This is placed
|
|
171
|
+
at matrix position ``[0, 1]``, matching R's ``groupShear``.
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
numpy.ndarray
|
|
176
|
+
A 3x3 affine shear matrix.
|
|
177
|
+
|
|
178
|
+
Examples
|
|
179
|
+
--------
|
|
180
|
+
>>> group_shear(0.5, 0)
|
|
181
|
+
array([[1. , 0. , 0. ],
|
|
182
|
+
[0.5, 1. , 0. ],
|
|
183
|
+
[0. , 0. , 1. ]])
|
|
184
|
+
"""
|
|
185
|
+
mat = np.eye(3, dtype=np.float64)
|
|
186
|
+
mat[0, 1] = sy
|
|
187
|
+
mat[1, 0] = sx
|
|
188
|
+
return mat
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def group_flip(flipX: bool = False, flipY: bool = False) -> Matrix3x3:
|
|
192
|
+
"""Return a 3x3 flip (reflection) matrix.
|
|
193
|
+
|
|
194
|
+
Parameters
|
|
195
|
+
----------
|
|
196
|
+
flipX : bool, optional
|
|
197
|
+
If ``True``, negate the *x*-component (reflect across the *y*-axis).
|
|
198
|
+
flipY : bool, optional
|
|
199
|
+
If ``True``, negate the *y*-component (reflect across the *x*-axis).
|
|
200
|
+
|
|
201
|
+
Returns
|
|
202
|
+
-------
|
|
203
|
+
numpy.ndarray
|
|
204
|
+
A 3x3 affine flip matrix.
|
|
205
|
+
|
|
206
|
+
Examples
|
|
207
|
+
--------
|
|
208
|
+
>>> group_flip(True, False)
|
|
209
|
+
array([[-1., 0., 0.],
|
|
210
|
+
[ 0., 1., 0.],
|
|
211
|
+
[ 0., 0., 1.]])
|
|
212
|
+
"""
|
|
213
|
+
mat = np.eye(3, dtype=np.float64)
|
|
214
|
+
if flipX:
|
|
215
|
+
mat[0, 0] = -1.0
|
|
216
|
+
if flipY:
|
|
217
|
+
mat[1, 1] = -1.0
|
|
218
|
+
return mat
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# ============================================================================
|
|
222
|
+
# Definition transforms (for defineGrob)
|
|
223
|
+
# ============================================================================
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def defn_translate(dx: float = 0, dy: float = 0) -> Matrix3x3:
|
|
227
|
+
"""Return a 3x3 translation matrix for a group definition.
|
|
228
|
+
|
|
229
|
+
In R this retrieves the definition viewport location from the group
|
|
230
|
+
object. Here we accept the displacements directly.
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
dx : float, optional
|
|
235
|
+
Horizontal displacement (default ``0``).
|
|
236
|
+
dy : float, optional
|
|
237
|
+
Vertical displacement (default ``0``).
|
|
238
|
+
|
|
239
|
+
Returns
|
|
240
|
+
-------
|
|
241
|
+
numpy.ndarray
|
|
242
|
+
A 3x3 affine translation matrix.
|
|
243
|
+
"""
|
|
244
|
+
return group_translate(dx, dy)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def defn_rotate(angle: float = 0) -> Matrix3x3:
|
|
248
|
+
"""Return a 3x3 rotation matrix for a group definition.
|
|
249
|
+
|
|
250
|
+
Parameters
|
|
251
|
+
----------
|
|
252
|
+
angle : float, optional
|
|
253
|
+
Rotation angle in degrees (default ``0``).
|
|
254
|
+
|
|
255
|
+
Returns
|
|
256
|
+
-------
|
|
257
|
+
numpy.ndarray
|
|
258
|
+
A 3x3 affine rotation matrix.
|
|
259
|
+
"""
|
|
260
|
+
return group_rotate(angle, device=True)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def defn_scale(sx: float = 1, sy: float = 1) -> Matrix3x3:
|
|
264
|
+
"""Return a 3x3 scaling matrix for a group definition.
|
|
265
|
+
|
|
266
|
+
Parameters
|
|
267
|
+
----------
|
|
268
|
+
sx : float, optional
|
|
269
|
+
Horizontal scale factor (default ``1``).
|
|
270
|
+
sy : float, optional
|
|
271
|
+
Vertical scale factor (default ``1``).
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
numpy.ndarray
|
|
276
|
+
A 3x3 affine scaling matrix.
|
|
277
|
+
"""
|
|
278
|
+
return group_scale(sx, sy)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
# ============================================================================
|
|
282
|
+
# Use transforms (for useGrob)
|
|
283
|
+
# ============================================================================
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def use_translate(dx: float = 0, dy: float = 0) -> Matrix3x3:
|
|
287
|
+
"""Return a 3x3 translation matrix for a group use.
|
|
288
|
+
|
|
289
|
+
In R this retrieves the current viewport location. Here we accept
|
|
290
|
+
the displacements directly so the matrix can be composed offline.
|
|
291
|
+
|
|
292
|
+
Parameters
|
|
293
|
+
----------
|
|
294
|
+
dx : float, optional
|
|
295
|
+
Horizontal displacement (default ``0``).
|
|
296
|
+
dy : float, optional
|
|
297
|
+
Vertical displacement (default ``0``).
|
|
298
|
+
|
|
299
|
+
Returns
|
|
300
|
+
-------
|
|
301
|
+
numpy.ndarray
|
|
302
|
+
A 3x3 affine translation matrix.
|
|
303
|
+
"""
|
|
304
|
+
return group_translate(dx, dy)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def use_rotate(angle: float = 0) -> Matrix3x3:
|
|
308
|
+
"""Return a 3x3 rotation matrix for a group use.
|
|
309
|
+
|
|
310
|
+
Parameters
|
|
311
|
+
----------
|
|
312
|
+
angle : float, optional
|
|
313
|
+
Rotation angle in degrees (default ``0``).
|
|
314
|
+
|
|
315
|
+
Returns
|
|
316
|
+
-------
|
|
317
|
+
numpy.ndarray
|
|
318
|
+
A 3x3 affine rotation matrix.
|
|
319
|
+
"""
|
|
320
|
+
return group_rotate(angle, device=True)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def use_scale(sx: float = 1, sy: float = 1) -> Matrix3x3:
|
|
324
|
+
"""Return a 3x3 scaling matrix for a group use.
|
|
325
|
+
|
|
326
|
+
Parameters
|
|
327
|
+
----------
|
|
328
|
+
sx : float, optional
|
|
329
|
+
Horizontal scale factor (default ``1``).
|
|
330
|
+
sy : float, optional
|
|
331
|
+
Vertical scale factor (default ``1``).
|
|
332
|
+
|
|
333
|
+
Returns
|
|
334
|
+
-------
|
|
335
|
+
numpy.ndarray
|
|
336
|
+
A 3x3 affine scaling matrix.
|
|
337
|
+
"""
|
|
338
|
+
return group_scale(sx, sy)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
# ============================================================================
|
|
342
|
+
# Viewport transforms
|
|
343
|
+
# ============================================================================
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def viewport_translate(dx: float = 0, dy: float = 0) -> Matrix3x3:
|
|
347
|
+
"""Return a 3x3 translation suitable for a viewport transform.
|
|
348
|
+
|
|
349
|
+
This is the combined inverse-definition-translate followed by the
|
|
350
|
+
use-translate, collapsed into a single translation of the difference.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
dx : float, optional
|
|
355
|
+
Net horizontal displacement (default ``0``).
|
|
356
|
+
dy : float, optional
|
|
357
|
+
Net vertical displacement (default ``0``).
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
numpy.ndarray
|
|
362
|
+
A 3x3 affine translation matrix.
|
|
363
|
+
"""
|
|
364
|
+
return group_translate(dx, dy)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def viewport_rotate(angle: float = 0) -> Matrix3x3:
|
|
368
|
+
"""Return a 3x3 rotation suitable for a viewport transform.
|
|
369
|
+
|
|
370
|
+
Parameters
|
|
371
|
+
----------
|
|
372
|
+
angle : float, optional
|
|
373
|
+
Net rotation angle in degrees (default ``0``).
|
|
374
|
+
|
|
375
|
+
Returns
|
|
376
|
+
-------
|
|
377
|
+
numpy.ndarray
|
|
378
|
+
A 3x3 affine rotation matrix.
|
|
379
|
+
"""
|
|
380
|
+
return group_rotate(angle, device=True)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def viewport_scale(sx: float = 1, sy: float = 1) -> Matrix3x3:
|
|
384
|
+
"""Return a 3x3 scaling suitable for a viewport transform.
|
|
385
|
+
|
|
386
|
+
Parameters
|
|
387
|
+
----------
|
|
388
|
+
sx : float, optional
|
|
389
|
+
Horizontal scale factor (default ``1``).
|
|
390
|
+
sy : float, optional
|
|
391
|
+
Vertical scale factor (default ``1``).
|
|
392
|
+
|
|
393
|
+
Returns
|
|
394
|
+
-------
|
|
395
|
+
numpy.ndarray
|
|
396
|
+
A 3x3 affine scaling matrix.
|
|
397
|
+
"""
|
|
398
|
+
return group_scale(sx, sy)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def viewport_transform(
|
|
402
|
+
dx: float = 0,
|
|
403
|
+
dy: float = 0,
|
|
404
|
+
rotation: float = 0,
|
|
405
|
+
sx: float = 1,
|
|
406
|
+
sy: float = 1,
|
|
407
|
+
) -> Matrix3x3:
|
|
408
|
+
"""Return a combined 3x3 viewport transform matrix.
|
|
409
|
+
|
|
410
|
+
The resulting matrix applies translation, rotation, and scaling in a
|
|
411
|
+
single affine transform, following the composition order used by R's
|
|
412
|
+
``viewportTransform``:
|
|
413
|
+
|
|
414
|
+
translate(dx, dy) @ rotate(rotation) @ scale(sx, sy)
|
|
415
|
+
|
|
416
|
+
Because we use the row-vector convention (``point @ matrix``), the
|
|
417
|
+
operations are applied left-to-right: first translate, then rotate,
|
|
418
|
+
then scale.
|
|
419
|
+
|
|
420
|
+
Parameters
|
|
421
|
+
----------
|
|
422
|
+
dx : float, optional
|
|
423
|
+
Horizontal translation (default ``0``).
|
|
424
|
+
dy : float, optional
|
|
425
|
+
Vertical translation (default ``0``).
|
|
426
|
+
rotation : float, optional
|
|
427
|
+
Rotation angle in degrees (default ``0``).
|
|
428
|
+
sx : float, optional
|
|
429
|
+
Horizontal scale factor (default ``1``).
|
|
430
|
+
sy : float, optional
|
|
431
|
+
Vertical scale factor (default ``1``).
|
|
432
|
+
|
|
433
|
+
Returns
|
|
434
|
+
-------
|
|
435
|
+
numpy.ndarray
|
|
436
|
+
A 3x3 combined affine transform matrix.
|
|
437
|
+
|
|
438
|
+
Examples
|
|
439
|
+
--------
|
|
440
|
+
>>> import numpy as np
|
|
441
|
+
>>> T = viewport_transform(dx=10, dy=20, rotation=0, sx=2, sy=3)
|
|
442
|
+
>>> np.allclose(T, group_translate(10, 20) @ group_scale(2, 3))
|
|
443
|
+
True
|
|
444
|
+
"""
|
|
445
|
+
T = group_translate(dx, dy)
|
|
446
|
+
R = group_rotate(rotation, device=True)
|
|
447
|
+
S = group_scale(sx, sy)
|
|
448
|
+
return T @ R @ S
|