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/_clippath.py ADDED
@@ -0,0 +1,170 @@
1
+ """Clipping-path system for grid_py.
2
+
3
+ Python port of R's ``grid`` package clipping-path infrastructure
4
+ (``grid/R/clippath.R``). Provides the :class:`GridClipPath` class and
5
+ the :func:`as_clip_path` factory function for converting a grob into a
6
+ clipping path.
7
+
8
+ Classes
9
+ -------
10
+ GridClipPath
11
+ A clipping path defined by a grob.
12
+
13
+ Functions
14
+ ---------
15
+ as_clip_path
16
+ Factory for :class:`GridClipPath`.
17
+ is_clip_path
18
+ Type-check predicate.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Any, List
24
+
25
+ __all__: List[str] = [
26
+ "GridClipPath",
27
+ "as_clip_path",
28
+ "is_clip_path",
29
+ ]
30
+
31
+
32
+ # ======================================================================
33
+ # GridClipPath
34
+ # ======================================================================
35
+
36
+
37
+ class GridClipPath:
38
+ """A clipping path wrapping a grob.
39
+
40
+ This is the Python equivalent of the R S3 class ``"GridClipPath"``
41
+ produced internally by ``createClipPath()``.
42
+
43
+ The clipping path constrains drawing to the region defined by the
44
+ referenced grob's outline.
45
+
46
+ Parameters
47
+ ----------
48
+ grob : Any
49
+ The grob object whose outline defines the clip region.
50
+
51
+ Raises
52
+ ------
53
+ TypeError
54
+ If *grob* is ``None``.
55
+
56
+ Examples
57
+ --------
58
+ >>> cp = GridClipPath("some_grob")
59
+ >>> cp.grob
60
+ 'some_grob'
61
+ """
62
+
63
+ __slots__ = ("_grob",)
64
+
65
+ def __init__(self, grob: Any) -> None:
66
+ if grob is None:
67
+ raise TypeError("a GridClipPath requires a non-None grob")
68
+ self._grob: Any = grob
69
+
70
+ # -- properties ---------------------------------------------------------
71
+
72
+ @property
73
+ def grob(self) -> Any:
74
+ """The grob whose outline defines the clipping region.
75
+
76
+ Returns
77
+ -------
78
+ Any
79
+ """
80
+ return self._grob
81
+
82
+ # -- dunder methods -----------------------------------------------------
83
+
84
+ def __repr__(self) -> str:
85
+ return f"GridClipPath(grob={self._grob!r})"
86
+
87
+ def __eq__(self, other: object) -> bool:
88
+ if isinstance(other, GridClipPath):
89
+ return self._grob == other._grob
90
+ return NotImplemented
91
+
92
+ def __hash__(self) -> int:
93
+ return hash(id(self._grob))
94
+
95
+
96
+ # ======================================================================
97
+ # Factory function
98
+ # ======================================================================
99
+
100
+
101
+ def as_clip_path(x: Any) -> GridClipPath:
102
+ """Convert a grob to a :class:`GridClipPath`.
103
+
104
+ This mirrors the intent of R's ``createClipPath()`` from the *grid*
105
+ package, exposed here as a user-facing factory function.
106
+
107
+ If *x* is already a :class:`GridClipPath` it is returned as-is,
108
+ avoiding unnecessary wrapping.
109
+
110
+ Parameters
111
+ ----------
112
+ x : Any
113
+ A grob instance, or an existing :class:`GridClipPath`.
114
+ ``None`` is **not** accepted.
115
+
116
+ Returns
117
+ -------
118
+ GridClipPath
119
+ A clipping-path object wrapping *x*.
120
+
121
+ Raises
122
+ ------
123
+ TypeError
124
+ If *x* is ``None``.
125
+
126
+ Examples
127
+ --------
128
+ >>> cp = as_clip_path("placeholder_grob")
129
+ >>> cp.grob
130
+ 'placeholder_grob'
131
+
132
+ Passing an existing ``GridClipPath`` returns it unchanged:
133
+
134
+ >>> cp2 = as_clip_path(cp)
135
+ >>> cp2 is cp
136
+ True
137
+ """
138
+ if isinstance(x, GridClipPath):
139
+ return x
140
+ if x is None:
141
+ raise TypeError("only a grob can be converted to a clipping path")
142
+ return GridClipPath(grob=x)
143
+
144
+
145
+ # ======================================================================
146
+ # Predicate
147
+ # ======================================================================
148
+
149
+
150
+ def is_clip_path(x: Any) -> bool:
151
+ """Return whether *x* is a :class:`GridClipPath` instance.
152
+
153
+ Parameters
154
+ ----------
155
+ x : Any
156
+ Object to test.
157
+
158
+ Returns
159
+ -------
160
+ bool
161
+ ``True`` if *x* is a :class:`GridClipPath`, ``False`` otherwise.
162
+
163
+ Examples
164
+ --------
165
+ >>> is_clip_path(as_clip_path("grob"))
166
+ True
167
+ >>> is_clip_path("not a clip path")
168
+ False
169
+ """
170
+ return isinstance(x, GridClipPath)