pysits 1.5.3.dev0__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.
- LICENSE +339 -0
- README.md +83 -0
- pysits/__init__.py +243 -0
- pysits/backend/__init__.py +18 -0
- pysits/backend/functions.py +50 -0
- pysits/backend/loaders.py +92 -0
- pysits/backend/pkgs.py +35 -0
- pysits/conversions/__init__.py +18 -0
- pysits/conversions/clojure.py +68 -0
- pysits/conversions/common.py +280 -0
- pysits/conversions/decorators.py +148 -0
- pysits/conversions/dsl/__init__.py +18 -0
- pysits/conversions/dsl/base.py +43 -0
- pysits/conversions/dsl/mask.py +337 -0
- pysits/conversions/dsl/tuning.py +129 -0
- pysits/conversions/tibble.py +444 -0
- pysits/conversions/tibble_arrow.py +469 -0
- pysits/conversions/vector.py +137 -0
- pysits/conversions/xarray.py +207 -0
- pysits/docs/__init__.py +22 -0
- pysits/docs/content/sits_get_data.md +85 -0
- pysits/docs/decorators.py +58 -0
- pysits/extras/__init__.py +82 -0
- pysits/extras/earthdatalogin.py +44 -0
- pysits/extras/torch.py +44 -0
- pysits/jinja.py +56 -0
- pysits/models/__init__.py +18 -0
- pysits/models/base.py +34 -0
- pysits/models/data/__init__.py +22 -0
- pysits/models/data/accuracy.py +94 -0
- pysits/models/data/base.py +51 -0
- pysits/models/data/cube.py +210 -0
- pysits/models/data/frame.py +138 -0
- pysits/models/data/frame_accessor.py +133 -0
- pysits/models/data/matrix.py +119 -0
- pysits/models/data/table.py +49 -0
- pysits/models/data/ts.py +161 -0
- pysits/models/data/tuning.py +307 -0
- pysits/models/data/vector.py +47 -0
- pysits/models/frame.py +191 -0
- pysits/models/ml.py +27 -0
- pysits/models/resolver.py +147 -0
- pysits/settings.py +44 -0
- pysits/sits/__init__.py +18 -0
- pysits/sits/classification.py +42 -0
- pysits/sits/colors.py +50 -0
- pysits/sits/config.py +45 -0
- pysits/sits/context.py +36 -0
- pysits/sits/cube.py +214 -0
- pysits/sits/data.py +220 -0
- pysits/sits/exporters/__init__.py +29 -0
- pysits/sits/exporters/files.py +37 -0
- pysits/sits/exporters/sf.py +30 -0
- pysits/sits/exporters/xarray.py +65 -0
- pysits/sits/impute.py +38 -0
- pysits/sits/ml.py +110 -0
- pysits/sits/segment.py +38 -0
- pysits/sits/tiles.py +35 -0
- pysits/sits/ts.py +216 -0
- pysits/sits/tuning.py +82 -0
- pysits/sits/utils.py +126 -0
- pysits/sits/visualization.py +122 -0
- pysits/templates/cube.html +196 -0
- pysits/templates/tuning.html +183 -0
- pysits/visualization/__init__.py +24 -0
- pysits/visualization/base.py +163 -0
- pysits/visualization/image.py +48 -0
- pysits/visualization/leaflet.py +94 -0
- pysits/visualization/tmap.py +85 -0
- pysits-1.5.3.dev0.dist-info/METADATA +123 -0
- pysits-1.5.3.dev0.dist-info/RECORD +73 -0
- pysits-1.5.3.dev0.dist-info/WHEEL +4 -0
- pysits-1.5.3.dev0.dist-info/licenses/LICENSE +339 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2025 sits developers.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify it
|
|
5
|
+
# under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
"""dsl module."""
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2025 sits developers.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify it
|
|
5
|
+
# under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
"""Base DSL classes."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DSLObject:
|
|
22
|
+
"""Base class for DSL classes."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RExpression(DSLObject):
|
|
26
|
+
def r_repr(self) -> str:
|
|
27
|
+
"""Convert the expression to its R representation.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
str: The R code string representation of the expression.
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
NotImplementedError: This method must be implemented by subclasses.
|
|
34
|
+
"""
|
|
35
|
+
raise NotImplementedError()
|
|
36
|
+
|
|
37
|
+
def __str__(self) -> str:
|
|
38
|
+
"""String representation of the R expression.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
str: The R code string representation.
|
|
42
|
+
"""
|
|
43
|
+
return self.r_repr()
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2025 sits developers.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify it
|
|
5
|
+
# under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
"""DSL for mask operations."""
|
|
19
|
+
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from pysits.conversions.dsl.base import RExpression
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Base R expression class
|
|
27
|
+
#
|
|
28
|
+
class MaskExpression(RExpression):
|
|
29
|
+
"""Mask expression class."""
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Magic methods
|
|
33
|
+
#
|
|
34
|
+
def __eq__(self, other):
|
|
35
|
+
return Eq(self, other)
|
|
36
|
+
|
|
37
|
+
def __ne__(self, other):
|
|
38
|
+
return Neq(self, other)
|
|
39
|
+
|
|
40
|
+
def __lt__(self, other):
|
|
41
|
+
return Lt(self, other)
|
|
42
|
+
|
|
43
|
+
def __le__(self, other):
|
|
44
|
+
return Le(self, other)
|
|
45
|
+
|
|
46
|
+
def __gt__(self, other):
|
|
47
|
+
return Gt(self, other)
|
|
48
|
+
|
|
49
|
+
def __ge__(self, other):
|
|
50
|
+
return Ge(self, other)
|
|
51
|
+
|
|
52
|
+
def __and__(self, other):
|
|
53
|
+
return And(self, other)
|
|
54
|
+
|
|
55
|
+
def __or__(self, other):
|
|
56
|
+
return Or(self, other)
|
|
57
|
+
|
|
58
|
+
def __invert__(self): # for ~expr → maps to ``NOT``
|
|
59
|
+
return Not(self)
|
|
60
|
+
|
|
61
|
+
def __mod__(self, other: Any) -> None:
|
|
62
|
+
"""Disabled modulo operator to prevent confusion with R's %in% operator.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
other: The right-hand operand (unused).
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
NotImplementedError: Always raised to indicate that %in_ should
|
|
69
|
+
be used instead.
|
|
70
|
+
"""
|
|
71
|
+
raise NotImplementedError("Use %in_ for 'in' operation")
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Hashing
|
|
75
|
+
#
|
|
76
|
+
def __hash__(self) -> int:
|
|
77
|
+
"""Hash the expression."""
|
|
78
|
+
return hash(self.r_repr())
|
|
79
|
+
|
|
80
|
+
#
|
|
81
|
+
# Abstract methods
|
|
82
|
+
#
|
|
83
|
+
def r_repr(self) -> str:
|
|
84
|
+
"""Convert the expression to its R string representation.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
str: The R code representation of the expression.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
NotImplementedError: This is an abstract method that must be implemented
|
|
91
|
+
by subclasses.
|
|
92
|
+
"""
|
|
93
|
+
raise NotImplementedError()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
#
|
|
97
|
+
# Helper function
|
|
98
|
+
#
|
|
99
|
+
def as_rexpr(x: int | float | str | MaskExpression) -> MaskExpression:
|
|
100
|
+
"""Convert a Python value to an R expression.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
x: Value to convert, can be an integer, float, string or
|
|
104
|
+
existing ``MaskExpression``.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
MaskExpression: The value wrapped in an appropriate
|
|
108
|
+
``MaskExpression`` subclass.
|
|
109
|
+
|
|
110
|
+
Raises:
|
|
111
|
+
TypeError: If the input type cannot be converted to an
|
|
112
|
+
``MaskExpression``s.
|
|
113
|
+
"""
|
|
114
|
+
if isinstance(x, MaskExpression):
|
|
115
|
+
return x
|
|
116
|
+
|
|
117
|
+
elif isinstance(x, (int | float | str)):
|
|
118
|
+
return Literal(x)
|
|
119
|
+
|
|
120
|
+
raise TypeError(f"Cannot convert {type(x)} to MaskExpression")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
#
|
|
124
|
+
# Variable (symbol)
|
|
125
|
+
#
|
|
126
|
+
class MaskVariable(MaskExpression):
|
|
127
|
+
"""Represents an R variable or symbol."""
|
|
128
|
+
|
|
129
|
+
def __init__(self, name: str) -> None:
|
|
130
|
+
self.name = name
|
|
131
|
+
|
|
132
|
+
def r_repr(self) -> str:
|
|
133
|
+
"""Convert the variable to its R string representation.
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
str: The variable name as it appears in R.
|
|
137
|
+
"""
|
|
138
|
+
return self.name
|
|
139
|
+
|
|
140
|
+
# Add mask %in_ [...] syntactic sugar
|
|
141
|
+
def in_(self, values: list[int | float | str]) -> "In":
|
|
142
|
+
"""Create an R %in% operation.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
values: List of values to check membership against.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
In: An expression representing `var %in% c(values)` in R.
|
|
149
|
+
"""
|
|
150
|
+
return In(self, values)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
# Literal value
|
|
155
|
+
#
|
|
156
|
+
class Literal(MaskExpression):
|
|
157
|
+
"""Represents a literal value in R code.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
value (Union[int, float, str]): The Python value to be represented in R.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
def __init__(self, value: int | float | str) -> None:
|
|
164
|
+
self.value = value
|
|
165
|
+
|
|
166
|
+
def r_repr(self) -> str:
|
|
167
|
+
"""Convert the literal to its R string representation.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
str: The R code representation of the literal value.
|
|
171
|
+
"""
|
|
172
|
+
return repr(self.value)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
#
|
|
176
|
+
# Binary operator
|
|
177
|
+
#
|
|
178
|
+
class BinaryOp(MaskExpression):
|
|
179
|
+
"""Base class for binary operators.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
left (Union[MaskExpression, int, float, str]): Left operand.
|
|
183
|
+
|
|
184
|
+
right (Union[MaskExpression, int, float, str]): Right operand.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
op: str | None = None
|
|
188
|
+
"""Operator."""
|
|
189
|
+
|
|
190
|
+
def __init__(
|
|
191
|
+
self,
|
|
192
|
+
left: MaskExpression | int | float | str,
|
|
193
|
+
right: MaskExpression | int | float | str,
|
|
194
|
+
) -> None:
|
|
195
|
+
self.left = as_rexpr(left)
|
|
196
|
+
self.right = as_rexpr(right)
|
|
197
|
+
|
|
198
|
+
def r_repr(self) -> str:
|
|
199
|
+
"""Convert the binary operation to its R string representation.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
str: The R code representation of the binary operation.
|
|
203
|
+
"""
|
|
204
|
+
return f"({self.left.r_repr()} {self.op} {self.right.r_repr()})"
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
#
|
|
208
|
+
# Specific binary ops
|
|
209
|
+
#
|
|
210
|
+
class Eq(BinaryOp):
|
|
211
|
+
"""Represents equality comparison (==) in R."""
|
|
212
|
+
|
|
213
|
+
op = "=="
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class Neq(BinaryOp):
|
|
217
|
+
"""Represents inequality comparison (!=) in R."""
|
|
218
|
+
|
|
219
|
+
op = "!="
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
class Lt(BinaryOp):
|
|
223
|
+
"""Represents less than comparison (<) in R."""
|
|
224
|
+
|
|
225
|
+
op = "<"
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class Le(BinaryOp):
|
|
229
|
+
"""Represents less than or equal comparison (<=) in R."""
|
|
230
|
+
|
|
231
|
+
op = "<="
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class Gt(BinaryOp):
|
|
235
|
+
"""Represents greater than comparison (>) in R."""
|
|
236
|
+
|
|
237
|
+
op = ">"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class Ge(BinaryOp):
|
|
241
|
+
"""Represents greater than or equal comparison (>=) in R."""
|
|
242
|
+
|
|
243
|
+
op = ">="
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
class And(BinaryOp):
|
|
247
|
+
"""Represents logical AND (&) in R."""
|
|
248
|
+
|
|
249
|
+
op = "&"
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class Or(BinaryOp):
|
|
253
|
+
"""Represents logical OR (|) in R."""
|
|
254
|
+
|
|
255
|
+
op = "|"
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
#
|
|
259
|
+
# Unary operator (NOT)
|
|
260
|
+
#
|
|
261
|
+
class Not(MaskExpression):
|
|
262
|
+
"""Represents logical NOT (!) in R.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
expr (Union[RExpr, int, float, str]): Expression to negate.
|
|
266
|
+
"""
|
|
267
|
+
|
|
268
|
+
def __init__(self, expr: MaskExpression | int | float | str) -> None:
|
|
269
|
+
self.expr = as_rexpr(expr)
|
|
270
|
+
|
|
271
|
+
def r_repr(self) -> str:
|
|
272
|
+
"""Convert the NOT operation to its R string representation.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
str: The R code representation of the NOT operation.
|
|
276
|
+
"""
|
|
277
|
+
return f"!({self.expr.r_repr()})"
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
#
|
|
281
|
+
# In operator: mask %in% c(...)
|
|
282
|
+
#
|
|
283
|
+
class In(MaskExpression):
|
|
284
|
+
"""Represents the %in% operator in R.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
left (Union[RExpr, int, float, str]): Value to check.
|
|
288
|
+
|
|
289
|
+
values (List[Union[int, float, str]]): List of values to check against.
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
def __init__(
|
|
293
|
+
self, left: MaskExpression | int | float | str, values: list[int | float | str]
|
|
294
|
+
) -> None:
|
|
295
|
+
self.left = as_rexpr(left)
|
|
296
|
+
self.values = values
|
|
297
|
+
|
|
298
|
+
def r_repr(self) -> str:
|
|
299
|
+
"""Convert the %in% operation to its R string representation.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
str: The R code representation of the %in% operation.
|
|
303
|
+
"""
|
|
304
|
+
values_str = ", ".join(repr(v) for v in self.values)
|
|
305
|
+
return f"{self.left.r_repr()} %in% c({values_str})"
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
#
|
|
309
|
+
# List of expressions
|
|
310
|
+
#
|
|
311
|
+
class MaskExpressionList(MaskExpression):
|
|
312
|
+
"""Represents a named list of R expressions.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
**entries (Dict[str, RExpr]): Keyword arguments mapping names to expressions.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
def __init__(self, **entries: dict[str, MaskExpression]) -> None:
|
|
319
|
+
self.entries = entries
|
|
320
|
+
|
|
321
|
+
def r_repr(self) -> str:
|
|
322
|
+
"""Convert the expression list to its R string representation.
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
str: The R code representation of the named list.
|
|
326
|
+
"""
|
|
327
|
+
entries_str = ",\n ".join(
|
|
328
|
+
f'"{key}" = {expr.r_repr()}' for key, expr in self.entries.items()
|
|
329
|
+
)
|
|
330
|
+
return f"list(\n {entries_str}\n)"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
#
|
|
334
|
+
# Mask variables
|
|
335
|
+
#
|
|
336
|
+
MaskValue = MaskVariable("mask")
|
|
337
|
+
"""Mask variable for reclassify operations."""
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2025 sits developers.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify it
|
|
5
|
+
# under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
"""DSL for tuning operations."""
|
|
19
|
+
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from pysits.conversions.dsl.base import RExpression
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TuningExpression(RExpression):
|
|
26
|
+
"""Tuning expression class."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class TuningSymbol(TuningExpression):
|
|
30
|
+
"""Represents an R symbol (variable or function name)."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, name: str) -> None:
|
|
33
|
+
"""Initializer."""
|
|
34
|
+
self.name = name
|
|
35
|
+
|
|
36
|
+
def r_repr(self) -> str:
|
|
37
|
+
"""Convert the symbol to its R representation."""
|
|
38
|
+
return self.name
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TuningFunctionCall(TuningExpression):
|
|
42
|
+
"""Represents an R function call."""
|
|
43
|
+
|
|
44
|
+
def __init__(self, func: str, *args: Any, **kwargs: Any) -> None:
|
|
45
|
+
"""Initialize an R function call.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
func: The name of the R function to call.
|
|
49
|
+
|
|
50
|
+
*args: Positional arguments for the function call.
|
|
51
|
+
|
|
52
|
+
**kwargs: Keyword arguments for the function call.
|
|
53
|
+
"""
|
|
54
|
+
self.func = func
|
|
55
|
+
self.args = args
|
|
56
|
+
self.kwargs = kwargs
|
|
57
|
+
|
|
58
|
+
def _convert_arg(self, arg: Any) -> str:
|
|
59
|
+
"""Convert a Python argument to its R representation.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
arg: The argument to convert. Can be an RExpr, dict, str, bool, None,
|
|
63
|
+
or any other type that can be converted to string.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
str: The R code string representation of the argument.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def _convert_dict(d: dict) -> str:
|
|
70
|
+
items = [f"{key} = {self._convert_arg(val)}" for key, val in d.items()]
|
|
71
|
+
return f"list({', '.join(items)})"
|
|
72
|
+
|
|
73
|
+
def _convert_string(s: str) -> str:
|
|
74
|
+
if "::" in s or s.isidentifier():
|
|
75
|
+
return TuningSymbol(s).r_repr()
|
|
76
|
+
return f'"{s}"'
|
|
77
|
+
|
|
78
|
+
def _convert_list(lvalue: list) -> str:
|
|
79
|
+
return f"c({', '.join(map(str, lvalue))})"
|
|
80
|
+
|
|
81
|
+
# Type converters
|
|
82
|
+
# ToDo: Merge with conversions.base types
|
|
83
|
+
type_converters = {
|
|
84
|
+
TuningExpression: lambda x: x.r_repr(),
|
|
85
|
+
dict: _convert_dict,
|
|
86
|
+
str: _convert_string,
|
|
87
|
+
list: _convert_list,
|
|
88
|
+
tuple: _convert_list,
|
|
89
|
+
bool: lambda x: "TRUE" if x else "FALSE",
|
|
90
|
+
type(None): lambda _: "NULL",
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
converter = type_converters.get(type(arg))
|
|
94
|
+
if converter is not None:
|
|
95
|
+
return converter(arg)
|
|
96
|
+
|
|
97
|
+
return str(arg)
|
|
98
|
+
|
|
99
|
+
def r_repr(self) -> str:
|
|
100
|
+
"""Convert the function call to its R representation.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
str: The R code string representation of the function call.
|
|
104
|
+
"""
|
|
105
|
+
args = [self._convert_arg(arg) for arg in self.args]
|
|
106
|
+
args.extend(
|
|
107
|
+
f"{key} = {self._convert_arg(val)}" for key, val in self.kwargs.items()
|
|
108
|
+
)
|
|
109
|
+
return f"{self.func}({', '.join(args)})"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def hparam(func_name: str, *args: Any, **kwargs: Any) -> TuningFunctionCall:
|
|
113
|
+
"""Create an R function call expression.
|
|
114
|
+
|
|
115
|
+
This function creates an R function call expression that can be used to represent
|
|
116
|
+
R function calls in Python code. The resulting expression can be converted to
|
|
117
|
+
R code using the ``r_repr()`` method.
|
|
118
|
+
|
|
119
|
+
Args:
|
|
120
|
+
func_name: The name of the R function to call.
|
|
121
|
+
|
|
122
|
+
*args: Positional arguments for the function call.
|
|
123
|
+
|
|
124
|
+
**kwargs: Keyword arguments for the function call.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
RCall: An R function call expression.
|
|
128
|
+
"""
|
|
129
|
+
return TuningFunctionCall(func_name, *args, **kwargs)
|