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.
Files changed (73) hide show
  1. LICENSE +339 -0
  2. README.md +83 -0
  3. pysits/__init__.py +243 -0
  4. pysits/backend/__init__.py +18 -0
  5. pysits/backend/functions.py +50 -0
  6. pysits/backend/loaders.py +92 -0
  7. pysits/backend/pkgs.py +35 -0
  8. pysits/conversions/__init__.py +18 -0
  9. pysits/conversions/clojure.py +68 -0
  10. pysits/conversions/common.py +280 -0
  11. pysits/conversions/decorators.py +148 -0
  12. pysits/conversions/dsl/__init__.py +18 -0
  13. pysits/conversions/dsl/base.py +43 -0
  14. pysits/conversions/dsl/mask.py +337 -0
  15. pysits/conversions/dsl/tuning.py +129 -0
  16. pysits/conversions/tibble.py +444 -0
  17. pysits/conversions/tibble_arrow.py +469 -0
  18. pysits/conversions/vector.py +137 -0
  19. pysits/conversions/xarray.py +207 -0
  20. pysits/docs/__init__.py +22 -0
  21. pysits/docs/content/sits_get_data.md +85 -0
  22. pysits/docs/decorators.py +58 -0
  23. pysits/extras/__init__.py +82 -0
  24. pysits/extras/earthdatalogin.py +44 -0
  25. pysits/extras/torch.py +44 -0
  26. pysits/jinja.py +56 -0
  27. pysits/models/__init__.py +18 -0
  28. pysits/models/base.py +34 -0
  29. pysits/models/data/__init__.py +22 -0
  30. pysits/models/data/accuracy.py +94 -0
  31. pysits/models/data/base.py +51 -0
  32. pysits/models/data/cube.py +210 -0
  33. pysits/models/data/frame.py +138 -0
  34. pysits/models/data/frame_accessor.py +133 -0
  35. pysits/models/data/matrix.py +119 -0
  36. pysits/models/data/table.py +49 -0
  37. pysits/models/data/ts.py +161 -0
  38. pysits/models/data/tuning.py +307 -0
  39. pysits/models/data/vector.py +47 -0
  40. pysits/models/frame.py +191 -0
  41. pysits/models/ml.py +27 -0
  42. pysits/models/resolver.py +147 -0
  43. pysits/settings.py +44 -0
  44. pysits/sits/__init__.py +18 -0
  45. pysits/sits/classification.py +42 -0
  46. pysits/sits/colors.py +50 -0
  47. pysits/sits/config.py +45 -0
  48. pysits/sits/context.py +36 -0
  49. pysits/sits/cube.py +214 -0
  50. pysits/sits/data.py +220 -0
  51. pysits/sits/exporters/__init__.py +29 -0
  52. pysits/sits/exporters/files.py +37 -0
  53. pysits/sits/exporters/sf.py +30 -0
  54. pysits/sits/exporters/xarray.py +65 -0
  55. pysits/sits/impute.py +38 -0
  56. pysits/sits/ml.py +110 -0
  57. pysits/sits/segment.py +38 -0
  58. pysits/sits/tiles.py +35 -0
  59. pysits/sits/ts.py +216 -0
  60. pysits/sits/tuning.py +82 -0
  61. pysits/sits/utils.py +126 -0
  62. pysits/sits/visualization.py +122 -0
  63. pysits/templates/cube.html +196 -0
  64. pysits/templates/tuning.html +183 -0
  65. pysits/visualization/__init__.py +24 -0
  66. pysits/visualization/base.py +163 -0
  67. pysits/visualization/image.py +48 -0
  68. pysits/visualization/leaflet.py +94 -0
  69. pysits/visualization/tmap.py +85 -0
  70. pysits-1.5.3.dev0.dist-info/METADATA +123 -0
  71. pysits-1.5.3.dev0.dist-info/RECORD +73 -0
  72. pysits-1.5.3.dev0.dist-info/WHEEL +4 -0
  73. 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)