cave-utils 2.2.1__tar.gz → 2.3.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.
Files changed (38) hide show
  1. {cave_utils-2.2.1/cave_utils.egg-info → cave_utils-2.3.0}/PKG-INFO +1 -1
  2. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/groupedOutputs.py +36 -5
  3. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/maps.py +28 -9
  4. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/pages.py +61 -15
  5. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/settings.py +82 -30
  6. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api_utils/general.py +119 -57
  7. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api_utils/validator_utils.py +21 -2
  8. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/geo_utils.py +3 -9
  9. {cave_utils-2.2.1 → cave_utils-2.3.0/cave_utils.egg-info}/PKG-INFO +1 -1
  10. {cave_utils-2.2.1 → cave_utils-2.3.0}/pyproject.toml +1 -1
  11. {cave_utils-2.2.1 → cave_utils-2.3.0}/setup.cfg +1 -1
  12. {cave_utils-2.2.1 → cave_utils-2.3.0}/LICENSE +0 -0
  13. {cave_utils-2.2.1 → cave_utils-2.3.0}/NOTICE.md +0 -0
  14. {cave_utils-2.2.1 → cave_utils-2.3.0}/README.md +0 -0
  15. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/__init__.py +0 -0
  16. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/__init__.py +0 -0
  17. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/appBar.py +0 -0
  18. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/extraKwargs.py +0 -0
  19. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/globalOutputs.py +0 -0
  20. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/mapFeatures.py +0 -0
  21. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api/panes.py +0 -0
  22. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api_utils/__init__.py +0 -0
  23. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/api_utils/validator.py +0 -0
  24. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/arguments.py +0 -0
  25. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/builders/__init__.py +0 -0
  26. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/builders/groups.py +0 -0
  27. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/log.py +0 -0
  28. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils/socket.py +0 -0
  29. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils.egg-info/SOURCES.txt +0 -0
  30. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils.egg-info/dependency_links.txt +0 -0
  31. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils.egg-info/requires.txt +0 -0
  32. {cave_utils-2.2.1 → cave_utils-2.3.0}/cave_utils.egg-info/top_level.txt +0 -0
  33. {cave_utils-2.2.1 → cave_utils-2.3.0}/test/test_arguments.py +0 -0
  34. {cave_utils-2.2.1 → cave_utils-2.3.0}/test/test_builders_groups.py +0 -0
  35. {cave_utils-2.2.1 → cave_utils-2.3.0}/test/test_geo_utils.py +0 -0
  36. {cave_utils-2.2.1 → cave_utils-2.3.0}/test/test_import.py +0 -0
  37. {cave_utils-2.2.1 → cave_utils-2.3.0}/test/test_log.py +0 -0
  38. {cave_utils-2.2.1 → cave_utils-2.3.0}/test/test_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cave_utils
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Python wrapper for api use in the cave_app
5
5
  Author-email: Connor Makowski <conmak@mit.edu>
6
6
  Project-URL: Homepage, https://github.com/mit-cave/cave_utils
@@ -123,9 +123,11 @@ class groupedOutputs_data_star_stats(ApiValidator):
123
123
  name: str,
124
124
  calculation: str,
125
125
  unit: [str, None] = None,
126
- unitPlacement: str = "afterWithSpace",
126
+ unitPlacement: [str, None] = None,
127
127
  precision: [int, None] = None,
128
- trailingZeros: bool = False,
128
+ trailingZeros: [bool, None] = None,
129
+ notation: [str, None] = None,
130
+ notationDisplay: [str, None] = None,
129
131
  **kwargs,
130
132
  ):
131
133
  """
@@ -156,11 +158,36 @@ class groupedOutputs_data_star_stats(ApiValidator):
156
158
  * **Notes**:
157
159
  * This ensures that all precision digits are shown. For example: `1.5` &rarr; `1.500` when precision is `3`.
158
160
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.trailingZeros`.
161
+ * **`notation`**: `[int]` = `"standard"` &rarr; The formatting style of a numeric value.
162
+ * **`notationDisplay`**: `[str]` = `"e+"` | `"short"` | `None` &rarr; Further customize the formatting within the selected `notation`.
163
+ * **Notes**:
164
+ * No `notationDisplay` option is provided for a `"standard"` notation
165
+ * The options `"short"` and `"long"` are only provided for the `"compact"` notation
166
+ * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"`, `"engineering"` and `"precision"` notations
167
+ * If `None`, it defaults to `"short"` for `"compact"` notation, and to `"e+"` for `"scientific"`, `"engineering"` or `"precision"` notations; if the option is set to `"standard"`, its value remains `None`.
168
+
169
+ [metric prefix]: https://en.wikipedia.org/wiki/Metric_prefix
170
+ [Scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
171
+ [Engineering notation]: https://en.wikipedia.org/wiki/Engineering_notation
172
+ [Number.prototype.toPrecision]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision
159
173
  """
174
+ passed_values = {k: v for k, v in locals().items() if (v is not None) and k != "kwargs"}
175
+ if notationDisplay and not notation:
176
+ raise Exception(f"Missing required fields: notation")
177
+ notation = passed_values.get("notation", "standard")
178
+
160
179
  return {
161
180
  "kwargs": kwargs,
162
181
  "accepted_values": {
163
182
  "unitPlacement": ["after", "afterWithSpace", "before", "beforeWithSpace"],
183
+ "notation": ["standard", "compact", "scientific", "engineering", "precision"],
184
+ "notationDisplay": {
185
+ "compact": ["short", "long"],
186
+ "scientific": ["e", "e+", "E", "E+", "x10^", "x10^+"],
187
+ "engineering": ["e", "e+", "E", "E+", "x10^", "x10^+"],
188
+ "precision": ["e", "e+", "E", "E+", "x10^", "x10^+"],
189
+ "standard": [],
190
+ }.get(notation, []),
164
191
  },
165
192
  }
166
193
 
@@ -268,6 +295,10 @@ class groupedOutputs_groupings_star(ApiValidator):
268
295
  * **`grouping`**: `[str]` = `None` &rarr;
269
296
  * A group that is created to put similar groupings together in the UI dropdowns when selecting groupings.
270
297
  * **Note**: If `None`, the grouping will be placed in the root of the UI dropdowns.
298
+
299
+ [metric prefix]: https://en.wikipedia.org/wiki/Metric_prefix
300
+ [Scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
301
+ [Engineering notation]: https://en.wikipedia.org/wiki/Engineering_notation
271
302
  """
272
303
  return {
273
304
  "kwargs": kwargs,
@@ -368,12 +399,12 @@ class groupedOutputs_groupings_star_levels_star(ApiValidator):
368
399
  * If `None`, this will be considered to be the root of the hierarchy.
369
400
  * **`ordering`**: `[list]` &rarr;
370
401
  * The ordering of individual values for this level in charts and tables.
371
- * **Note**: If none, the ordering will be alphabetical.
402
+ * **Note**: If `None`, the ordering will be alphabetical.
372
403
  * **Note**: If a partial ordering is provided, the provided values will be placed first in order.
373
404
  * **Note**: If a partial ordering is provided, the remaining values will be placed in alphabetical order.
374
405
  * **Note**: All items in this list must be defined in `groupedOutputs.groupings.*.levels.*.values.*`
375
- * **`orderWithParent`**: `[bool]`=True &rarr;
376
- * Weather or not to order this level based on the parent level.
406
+ * **`orderWithParent`**: `[bool]` = `True` &rarr;
407
+ * Wether or not to order this level based on the parent level.
377
408
  * If `True`, the ordering of this level will also be based on the parent level.
378
409
  * If `False`, the ordering will be based on the ordering of this level only.
379
410
  * **`coloring`**: `[dict]` &rarr;
@@ -311,13 +311,13 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
311
311
  * `"solid"`: Represents a single continuous line.
312
312
  * `"dashed"`: A series of dashes or line segments
313
313
  * `"dotted"`: A dotted line
314
- * **Note**: This attribute is applicable exclusively to `arc` layers.
314
+ * **Note**: This attribute applies exclusively to `arc` layers.
315
315
  * **`allowGrouping`**: `[bool]` = `False` &rarr; Whether or not to allow grouping of the data layer.
316
- * **Note**: This attribute is applicable exclusively to `node` layers.
316
+ * **Note**: This attribute applies exclusively to `node` layers.
317
317
  * **`group`**: `[bool]` = `False` &rarr; Whether or not to group the data layer.
318
318
  * **Notes**:
319
319
  * If `False`, the data layer will not be grouped
320
- * This attribute is applicable exclusively to `node` layers
320
+ * This attribute applies exclusively to `node` layers
321
321
  * **`groupCalcBySize`**: `[str]` = `"count"` | `"mode"` &rarr; The aggregation function to use on the prop specified in `sizeBy`.
322
322
  * **Accepted Values**:
323
323
  * When **`sizeBy`** prop's **`type`** == `"num"`:
@@ -338,7 +338,7 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
338
338
  * If `None`, the data layer will not be grouped
339
339
  * The calculation is based on the values of the prop specified in `sizeBy`
340
340
  * The default value for a `sizeBy` prop of type `"num"` is `"count"`. For other types, the default value is `"mode"`.
341
- * This attribute is applicable exclusively to `node` layers
341
+ * This attribute applies exclusively to `node` layers
342
342
  * **`groupCalcByColor`**: `[str]` = `"count"` | `"mode"` &rarr; The aggregation function to use on the prop specified in `colorBy`.
343
343
  * **Accepted Values**:
344
344
  * When **`colorBy`** prop's **`type`** == `"num"`:
@@ -359,15 +359,15 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
359
359
  * If `None`, the data layer will not be grouped
360
360
  * The calculation is based on the prop specified in `colorBy`
361
361
  * The default value for a `colorBy` prop of type `"num"` is `"count"`. For other types, the default value is `"mode"`.
362
- * This attribute is applicable exclusively to `node` layers
362
+ * This attribute applies exclusively to `node` layers
363
363
  * **`groupScaleWithZoom`**: `[bool]` = `False` &rarr; Whether or not to scale the group size with zoom.
364
364
  * **Notes**:
365
365
  * If `False`, the group size will be constant as set by `groupScale`
366
- * This attribute is applicable exclusively to `node` layers
366
+ * This attribute applies exclusively to `node` layers
367
367
  * **`groupScale`**: `[float | int]` = `None` &rarr; The zoom level at which to conduct grouping of the nodes.
368
368
  * **Notes**:
369
369
  * If `None`, the group scale will be determined by the map zoom.
370
- * This attribute is applicable exclusively to `node` layers
370
+ * This attribute applies exclusively to `node` layers
371
371
  * **`colorByOptions`**: `[dict]` = `None` &rarr; The options for coloring the data layer.
372
372
  * **Notes**:
373
373
  * If `None`, the data layer will not be colored.
@@ -411,7 +411,7 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
411
411
  * **Notes**:
412
412
  * Arc layer icons are determined by `lineBy`.
413
413
  * Shape layer icons are always the default icon.
414
- * This attribute is applicable exclusively to `node` layers
414
+ * This attribute applies exclusively to `node` layers
415
415
  """
416
416
  return {
417
417
  "kwargs": kwargs,
@@ -459,7 +459,8 @@ class maps_data_star_legendGroups_star_data_star(ApiValidator):
459
459
  if v.get("type") in ["num", "toggle", "selector", "text"]
460
460
  }
461
461
  sizeBy_availableProps = {
462
- k: v for k, v in available_props.items() if v.get("type") in ["num"]
462
+ k: v for k, v in available_props.items()
463
+ if v.get("type") in ["num", "toggle", "selector"]
463
464
  }
464
465
 
465
466
  passed_colorByOptions = self.data.get("colorByOptions", {})
@@ -687,5 +688,23 @@ class sizeByOptions(ApiValidator):
687
688
  if not isinstance(obj_val, (int, float)):
688
689
  self.__error__(msg=f"Invalid `{obj_key}` ({obj_val}) must be a number")
689
690
  continue
691
+ elif prop_type == "toggle":
692
+ for key, value in self.data.items():
693
+ if not self.__check_subset_valid__(
694
+ subset=[key],
695
+ valid_values=["true", "false", "nullSize"],
696
+ prepend_path=[],
697
+ ):
698
+ return
699
+ self.__check_pixel_string_valid__(pixel_string=value, prepend_path=[key])
700
+ elif prop_type == "selector":
701
+ for key, value in self.data.items():
702
+ if not self.__check_subset_valid__(
703
+ subset=[key],
704
+ valid_values=list(prop_data.get("options").keys()) + ["nullSize"],
705
+ prepend_path=[],
706
+ ):
707
+ return
708
+ self.__check_pixel_string_valid__(pixel_string=value, prepend_path=[key])
690
709
  else:
691
710
  self.__error__(msg=f"Invalid prop type ({prop_type}) for sizeByOptions")
@@ -2,9 +2,11 @@
2
2
  Configure your application's pages.
3
3
  """
4
4
 
5
- from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
6
5
  import type_enforced
7
6
 
7
+ from itertools import chain
8
+ from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
9
+
8
10
 
9
11
  @type_enforced.Enforcer
10
12
  class pages(ApiValidator):
@@ -84,6 +86,10 @@ class pages_data_star_pageLayout(ApiValidator):
84
86
  showToolbar: bool = True,
85
87
  maximized: bool = False,
86
88
  defaultToZero: bool = False,
89
+ distributionType: [str, None] = None,
90
+ distributionYAxis: [str, None] = None,
91
+ distributionVariant: [str, None] = None,
92
+ showNA: bool = False,
87
93
  **kwargs,
88
94
  ):
89
95
  """
@@ -112,6 +118,7 @@ class pages_data_star_pageLayout(ApiValidator):
112
118
  * `"table"`: A table showing the aggregated values.
113
119
  * `"treemap"`: A [treemap chart][]
114
120
  * `"waterfall"`: A [waterfall chart][]
121
+ * `"distribution"`: A [distribution chart][]
115
122
  * When **`type`** == `"globalOutput"`:
116
123
  * `"bar"`: A [bar chart][]
117
124
  * `"line"`: A [line chart][]
@@ -138,6 +145,28 @@ class pages_data_star_pageLayout(ApiValidator):
138
145
  * **`maximized`**: `[bool]` = `False` &rarr; Whether or not the layout should be maximized.
139
146
  * **Note**: If more than one chart belonging to the same page layout is set to `True`, the first one found in the list will take precedence.
140
147
  * **`defaultToZero`**: `[bool]` = `False` &rarr; Whether or not the chart should default missing values to zero.
148
+ * **`distributionType`**: `[str]` = `None` &rarr; The type of distribution function displayed in distribution charts.
149
+ * Accepted Values:
150
+ * `"pdf"`: Uses the probability density function.
151
+ * `"cdf"`: Uses the cumulative density function.
152
+ * **Notes**:
153
+ * If left unspecified (i.e., `None`), it will default to `"pdf"`.
154
+ * This attribute is applicable exclusively to the `"distribution"` variant.
155
+ * **`distributionYAxis`**: `[str]` = `None` &rarr; The y-axis metric in distribution charts.
156
+ * Accepted Values:
157
+ * `"counts"`: Displays the y-axis as raw counts of occurrences.
158
+ * `"density"`: Displays the y-axis as proportions of total counts.
159
+ * **Notes**:
160
+ * If left unspecified (i.e., `None`), it will default to `"counts"`.
161
+ * This attribute is applicable exclusively to the `"distribution"` variant.
162
+ * **`distributionVariant`**: `[str]` = `None` &rarr; The chart type displayed in distribution charts.
163
+ * Accepted Values:
164
+ * `"bar"`: A bar chart.
165
+ * `"line"`: A line chart.
166
+ * **Notes**:
167
+ * If left unspecified (i.e., `None`), it will default to `"bar"`.
168
+ * This attribute is applicable exclusively to the `"distribution"` variant.
169
+ * **`showNA`**: `[bool]` = `False` &rarr; Whether to display missing or filtered values in both the chart tooltip and the axis.
141
170
 
142
171
  [area chart]: https://en.wikipedia.org/wiki/Area_chart
143
172
  [bar chart]: https://en.wikipedia.org/wiki/Bar_chart
@@ -154,6 +183,7 @@ class pages_data_star_pageLayout(ApiValidator):
154
183
  [table chart]: #
155
184
  [treemap chart]: https://en.wikipedia.org/wiki/Treemapping
156
185
  [waterfall chart]: https://en.wikipedia.org/wiki/Waterfall_chart
186
+ [distribution chart]: https://en.wikipedia.org/wiki/Probability_distribution
157
187
  """
158
188
  if type == "globalOutput":
159
189
  variant_options = ["bar", "line", "table", "overview"]
@@ -168,12 +198,14 @@ class pages_data_star_pageLayout(ApiValidator):
168
198
  "heatmap",
169
199
  "line",
170
200
  "scatter",
201
+ "distribution",
171
202
  "stacked_area",
172
203
  "stacked_waterfall",
173
204
  "sunburst",
174
205
  "table",
175
206
  "treemap",
176
207
  "waterfall",
208
+ "distribution",
177
209
  ]
178
210
  else:
179
211
  variant_options = []
@@ -183,6 +215,9 @@ class pages_data_star_pageLayout(ApiValidator):
183
215
  "type": ["groupedOutput", "globalOutput", "map"],
184
216
  "variant": variant_options,
185
217
  "statAggregation": ["sum", "mean", "min", "max"],
218
+ "distributionType": ["pdf", "cdf"] if variant == "distribution" else [],
219
+ "distributionYAxis": ["counts", "density"] if variant == "distribution" else [],
220
+ "distributionVariant": ["bar", "line"] if variant == "distribution" else [],
186
221
  },
187
222
  }
188
223
 
@@ -219,45 +254,56 @@ class pages_data_star_pageLayout(ApiValidator):
219
254
  # Validate groupedOutput
220
255
  else:
221
256
  # Validate groupedOutputDataId
222
- groupedOutputDataId = self.data.get("groupedOutputDataId")
257
+ groupedOutputDataId_raw = self.data.get("groupedOutputDataId")
258
+ groupedOutputDataId = (
259
+ [groupedOutputDataId_raw]
260
+ if isinstance(groupedOutputDataId_raw, str)
261
+ else groupedOutputDataId_raw
262
+ )
223
263
  if groupedOutputDataId is not None:
224
264
  self.__check_type__(
225
265
  groupedOutputDataId, (str, list), prepend_path=["groupedOutputDataId"]
226
266
  )
227
- # TODO: Review subset validation
228
267
  # Ensure that the groupedOutputDataId is valid
229
268
  self.__check_subset_valid__(
230
- subset=[groupedOutputDataId],
269
+ subset=groupedOutputDataId,
231
270
  valid_values=list(kwargs.get("groupedOutputs_validGroupIds", {}).keys()),
232
271
  prepend_path=["groupedOutputDataId"],
233
272
  )
234
273
  # Validate statId
235
- statId = self.data.get("statId")
236
- if statId is not None:
237
- self.__check_type__(statId, (str, list), prepend_path=["statId"])
238
- statIds = statId if isinstance(statId, list) else [statId]
239
- # TODO: Review subset validation
240
- for sid in statIds:
274
+ statId_raw = self.data.get("statId")
275
+ if statId_raw is not None:
276
+ self.__check_type__(statId_raw, (str, list), prepend_path=["statId"])
277
+ statId = statId_raw if isinstance(statId_raw, list) else [statId_raw]
278
+ if len(groupedOutputDataId) != len(statId):
279
+ self.__error__(
280
+ msg="`groupingId` and `statId` must be the same length.",
281
+ )
282
+ return
283
+ for idx, sid in enumerate(statId):
241
284
  # Ensure that the statId is valid
242
285
  self.__check_subset_valid__(
243
286
  subset=[sid],
244
287
  valid_values=list(
245
288
  kwargs.get("groupedOutputs_validStatIds", {}).get(
246
- groupedOutputDataId, []
289
+ groupedOutputDataId[idx], []
247
290
  )
248
291
  ),
249
- prepend_path=["statId"],
292
+ prepend_path=["statId", idx],
250
293
  )
251
294
  # Validate groupingId
252
295
  groupingId = self.data.get("groupingId")
253
296
  if groupingId is not None:
254
297
  self.__check_type__(groupingId, list, prepend_path=["groupingId"])
298
+ all_valid_group_ids = chain.from_iterable([
299
+ kwargs.get("groupedOutputs_validGroupIds", {}).get(groupingId_item, [])
300
+ for groupingId_item in groupedOutputDataId
301
+ ])
302
+ valid_values = list(set(all_valid_group_ids))
255
303
  # Ensure that the groupingId is valid
256
304
  self.__check_subset_valid__(
257
305
  subset=groupingId,
258
- valid_values=list(
259
- kwargs.get("groupedOutputs_validGroupIds", {}).get(groupedOutputDataId, [])
260
- ),
306
+ valid_values=valid_values,
261
307
  prepend_path=["groupingId"],
262
308
  )
263
309
  # Validate groupingLevel
@@ -88,13 +88,13 @@ class settings_defaults(ApiValidator):
88
88
  locale: str = "en-US",
89
89
  precision: int = 2,
90
90
  trailingZeros: bool = False,
91
- notation: [str, None] = "standard",
91
+ notation: [str, None] = None,
92
92
  notationDisplay: [str, None] = None,
93
93
  fallbackValue: [str, None] = "N/A",
94
94
  unit: [str, None] = None,
95
- unitPlacement: str = "afterWithSpace",
95
+ unitPlacement: [str, None] = None,
96
96
  legendPrecision: [str, None] = None,
97
- legendNotation: [str, None] = "standard",
97
+ legendNotation: [str, None] = None,
98
98
  legendNotationDisplay: [str, None] = None,
99
99
  legendMinLabel: [str, None] = None,
100
100
  legendMaxLabel: [str, None] = None,
@@ -106,50 +106,73 @@ class settings_defaults(ApiValidator):
106
106
  * **`showToolbar`**: `[bool]` = `True` &rarr; If `True`, chart toolbars will be displayed by default.
107
107
  * **`locale`**: `[str]` = `"en-US"` &rarr;
108
108
  * Format numeric values based on language and regional conventions.
109
- * **Note**: This attribute only applies to `"num"` props.
109
+ * **Note**: This attribute only applies to `"num"` props or `stats`.
110
110
  * **See**: [Locale identifier][].
111
111
  * **`precision`**: `[int]` = `2` &rarr; The number of decimal places to display.
112
112
  * **Notes**:
113
113
  * Set the precision to `0` to attach an integer constraint.
114
- * This attribute only applies to `"num"` props.
114
+ * This attribute only applies to `"num"` props or `stats`.
115
115
  * **`trailingZeros`**: `[bool]` = `False` &rarr; If `True`, trailing zeros will be displayed.
116
116
  * **Notes**:
117
117
  * This ensures that all precision digits are shown. For example: `1.5` &rarr; `1.500` when precision is `3`.
118
- * This attribute only applies to `"num"` props.
118
+ * This attribute only applies to `"num"` props or `stats`.
119
119
  * **`notation`**: `[int]` = `"standard"` &rarr; The formatting style of a numeric value.
120
+ * **Accepted Values**:
121
+ * `"standard"`: Plain number formatting
122
+ * `"compact"`: Resembles the [metric prefix][] system
123
+ * `"scientific"`: [Scientific notation][]
124
+ * `"engineering"`: [Engineering notation][]
125
+ * `"precision"`: Emulates the [Number.prototype.toPrecision][] method
126
+ * **Notes**:
127
+ * If left unspecified (i.e. `None`), the prop's or stat's `notation` will be used or in case the latter is undefined, `settings.notation` will be used.
128
+ * This attribute only applies to `"num"` props or `stats`.
120
129
  * **`notationDisplay`**: `[str]` = `"e+"` | `"short"` | `None` &rarr; Further customize the formatting within the selected `notation`.
130
+ * **Accepted Values**:
131
+ * When **`notation`** == `"compact"`:
132
+ * `"short"`: Add symbols `K`, `M`, `B`, and `T` (in `"en-US"`) to denote thousands, millions, billions, and trillions, respectively.
133
+ * `"long"`: Present numeric values with the informal suffix words `thousand`, `million`, `billion`, and `trillion` (in `"en-US"`).
134
+ * When **`notation`** == `"scientific"`, `"engineering"` or `"precision"`:
135
+ * `"e"`: Exponent symbol in lowercase as per the chosen `locale` identifier
136
+ * `"e+"`: Similar to `"e"`, but with a plus sign for positive exponents.
137
+ * `"E"`: Exponent symbol in uppercase as per the chosen `locale` identifier
138
+ * `"E+"`: Similar to `"E"`, but with a plus sign for positive exponents.
139
+ * `"x10^"`: Formal scientific notation representation
140
+ * `"x10^+"`: Similar to `"x10^"`, with a plus sign for positive exponents.
141
+ * When **`notation`** == `"standard"`:
142
+ * No `notationDisplay` option is allowed for a `"standard"` notation
121
143
  * **Notes**:
122
144
  * No `notationDisplay` option is provided for a `"standard"` notation
123
145
  * The options `"short"` and `"long"` are only provided for the `"compact"` notation
124
- * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"` and `"engineering"` notations
125
- * If `None`, it defaults to `"short"` for `"compact"` notation, and to `"e+"` for `"scientific"` or `"engineering"` notations; if the option is set to `"standard"`, its value remains `None`.
126
- * This attribute only applies to `"num"` props.
146
+ * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"`, `"engineering"` and `"precision"` notations
147
+ * If `None`, it defaults to `"short"` for `"compact"` notation, and to `"e+"` for `"scientific"`, `"engineering"`, or `"precision"` notations. For the `"standard"` option, the value remains `None`.
148
+ * This attribute only applies to `"num"` props or `stats`.
127
149
  * **`fallbackValue`**: [str] = `"N/A"` &rarr; A value to show when a numeric value is missing or invalid.
128
- * **Note**: This attribute only applies to `"num"` props.
150
+ * **Note**: This attribute only applies to `"num"` props or `stats`.
129
151
  * **`unit`**: `[str]` = `None` &rarr; The unit to use for a prop or stat.
130
- * **Note**: This attribute only applies to `"num"` props.
152
+ * **Note**: This attribute only applies to `"num"` props or `stats`.
131
153
  * **`unitPlacement`**: `[str]` = `"afterWithSpace"` &rarr; The position of the `unit` symbol relative to a value.
132
154
  * **Accepted Values**:
133
155
  * `"after"`: The `unit` appears after the value.
134
156
  * `"afterWithSpace"`: The `unit` appears after the value, separated by a space.
135
157
  * `"before"`: The `unit` appears before the value.
136
158
  * `"beforeWithSpace"`: The unit is placed before the value, with a space in between.
137
- * **Note**: This attribute only applies to `"num"` props.
159
+ * **Note**: This attribute only applies to `"num"` props or `stats`.
138
160
  * **`legendPrecision`**: `[int]` = `None` &rarr;
139
161
  * The number of decimal places to display in the Map Legend.
140
162
  * **Notes**:
141
163
  * Set the precision to `0` to attach an integer constraint.
142
- * If left unspecified (i.e. `None`), the prop's `precision` will be used or in case the latter is undefined, `settings.precision` will be used.
143
- * This attribute only applies to `"num"` props.
164
+ * If left unspecified (i.e. `None`), the prop's or stat's `precision` will be used or in case the latter is undefined, `settings.precision` will be used.
165
+ * This attribute only applies to `"num"` props or `stats`.
144
166
  * **`legendNotation`**: `[int]` = `"standard"` &rarr; The formatting style of a numeric value.
145
167
  * **Accepted Values**:
146
168
  * `"standard"`: Plain number formatting
147
169
  * `"compact"`: Resembles the [metric prefix][] system
148
170
  * `"scientific"`: [Scientific notation][]
149
171
  * `"engineering"`: [Engineering notation][]
172
+ * `"precision"`: Emulates the [Number.prototype.toPrecision][] method
150
173
  * **Notes**:
151
- * If left unspecified (i.e. `None`), the prop's `notation` will be used or in case the latter is undefined, `settings.notation` will be used.
152
- * This attribute only applies to `"num"` props.
174
+ * If left unspecified (i.e. `None`), the prop's or stat's `notation` will be used or in case the latter is undefined, `settings.notation` will be used.
175
+ * This attribute only applies to `"num"` props or `stats`.
153
176
  * **`legendNotationDisplay`**: `[str]` = `"e+"` | `"short"` | `None` &rarr; Further customize the formatting within the selected `legendNotation`.
154
177
  * **Accepted Values**:
155
178
  * `"short"`: Add symbols `K`, `M`, `B`, and `T` (in `"en-US"`) to denote thousands, millions, billions, and trillions, respectively.
@@ -163,34 +186,53 @@ class settings_defaults(ApiValidator):
163
186
  * **Notes**:
164
187
  * No `legendNotationDisplay` option is provided for a `"standard"` legend notation
165
188
  * The options `"short"` and `"long"` are only provided for the `"compact"` legend notation
166
- * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"` and `"engineering"` legend notations
167
- * If left unspecified (i.e. `None`), the prop's `notationDisplay` will be used or in case the latter is undefined, `settings.notationDisplay` will be used.
168
- * This attribute only applies to `"num"` props.
189
+ * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"`, `"engineering"` and `"precision"` legend notations
190
+ * If left unspecified (i.e. `None`), the prop's or stat's `notationDisplay` will be used or in case the latter is undefined, `settings.notationDisplay` will be used.
191
+ * This attribute only applies to `"num"` props or `stats`.
169
192
  * **`legendMinLabel`**: `[str]` = `None` &rarr;
170
193
  * A custom and descriptive label in the Map Legend used to identify the lowest data point.
171
194
  * **Notes**:
172
195
  * Takes precedence over other formatting, except when used in a node cluster and the `cave_utils.api.maps.group` attribute is `True`. In this case, the min value within the node cluster is displayed.
173
- * This attribute only applies to `"num"` props.
196
+ * This attribute only applies to `"num"` props or `stats`.
174
197
  * **`legendMaxLabel`**: `[str]` = `None` &rarr;
175
198
  * A custom and descriptive label in the Map Legend used to identify the highest data point.
176
199
  * **Notes**:
177
200
  * Takes precedence over other formatting, except when used in a node cluster and the `cave_utils.api.maps.group` attribute is `True`. In this case, the max value within the node cluster is displayed.
178
- * This attribute only applies to `"num"` props.
201
+ * This attribute only applies to `"num"` props or `stats`.
179
202
 
180
203
  [locale identifier]: https://en.wikipedia.org/wiki/IETF_language_tag
204
+ [metric prefix]: https://en.wikipedia.org/wiki/Metric_prefix
205
+ [Scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
206
+ [Engineering notation]: https://en.wikipedia.org/wiki/Engineering_notation
207
+ [Number.prototype.toPrecision]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision
181
208
  """
209
+ passed_values = {k: v for k, v in locals().items() if (v is not None) and k != "kwargs"}
210
+ required_fields = []
211
+ if notationDisplay:
212
+ required_fields += ["notation"]
213
+ if legendNotationDisplay:
214
+ required_fields += ["legendNotation"]
215
+ missing_required = pamda.difference(required_fields, list(passed_values.keys()))
216
+ if len(missing_required) > 0:
217
+ raise Exception(f"Missing required fields: {str(missing_required)}")
218
+
219
+ notationDisplay_options_dict = {
220
+ "compact": ["short", "long"],
221
+ "scientific": ["e", "e+", "E", "E+", "x10^", "x10^+"],
222
+ "engineering": ["e", "e+", "E", "E+", "x10^", "x10^+"],
223
+ "precision": ["e", "e+", "E", "E+", "x10^", "x10^+"],
224
+ "standard": [],
225
+ }
226
+ notation = passed_values.get("notation", "standard")
227
+ legendNotation = passed_values.get("legendNotation", "standard")
182
228
  return {
183
229
  "kwargs": kwargs,
184
230
  "accepted_values": {
185
231
  "unitPlacement": ["after", "afterWithSpace", "before", "beforeWithSpace"],
186
- # TODO: Validate
187
- # compact: allowed notation displays -> "short", "long"
188
- # scientific|engineering: allowed notation displays -> "e", "e+", "E", "E+", "x10^", "x10^+"
189
- # standard: allowed notation displays -> None
190
- "notation": ["compact", "precision", "scientific"],
191
- "notationDisplay": ["short", "long", "e", "e+", "E", "E+", "x10^", "x10^+"],
192
- "legendNotation": ["compact", "precision", "scientific"],
193
- "legendNotationDisplay": ["short", "long", "e", "e+", "E", "E+", "x10^", "x10^+"],
232
+ "notation": ["standard", "compact", "scientific", "engineering", "precision"],
233
+ "notationDisplay": notationDisplay_options_dict.get(notation, []),
234
+ "legendNotation": ["standard", "compact", "scientific", "engineering", "precision"],
235
+ "legendNotationDisplay": notationDisplay_options_dict.get(legendNotation, []),
194
236
  },
195
237
  }
196
238
 
@@ -283,13 +325,16 @@ class settings_time(ApiValidator):
283
325
  """
284
326
 
285
327
  @staticmethod
286
- def spec(timeLength: int, timeUnits: str, **kwargs):
328
+ def spec(timeLength: int, timeUnits: str, looping: bool, speed: [float, int], **kwargs):
287
329
  """
288
330
  Arguments:
289
331
 
290
332
  * **`timeLength`**: `[int]` &rarr; The amount of time values to display.
291
333
  * **`timeUnits`**: `[str]` &rarr; The units of time to display.
292
334
  * **Example**: `"Decade"`.
335
+ * **`looping`**: `[bool]` &rarr; If `True`, the time animation will automatically restart from the beginning once it reaches the end.
336
+ * **`speed`**: `[float]` &rarr; The speed at which the animation advances to the next time step.
337
+ * **Note**: While `speed` is intended to be measured in frames per second (fps), performance may degrade as the size of the time-varying data increases, resulting in slower animation.
293
338
  """
294
339
  return {"kwargs": kwargs, "accepted_values": {}}
295
340
 
@@ -297,3 +342,10 @@ class settings_time(ApiValidator):
297
342
  timeLength = self.data.get("timeLength")
298
343
  if timeLength < 1:
299
344
  self.__error__(f"Time length must be greater than 0.", path=["timeLength"])
345
+ speed = self.data.get("speed")
346
+ accepted_speed_values = {0.5, 0.75, 1, 1.25, 1.5, 2}
347
+ if speed not in accepted_speed_values:
348
+ self.__error__(
349
+ f"speed must be one of the following values: {accepted_speed_values}.",
350
+ path=["speed"],
351
+ )
@@ -17,9 +17,12 @@ class props(ApiValidator):
17
17
  variant: [str, None] = None,
18
18
  display: [bool, None] = None,
19
19
  enabled: [bool, None] = None,
20
+ container: [str, None] = None,
20
21
  apiCommand: [str, None] = None,
21
22
  apiCommandKeys: [list[str], None] = None,
22
23
  options: [dict, None] = None,
24
+ valueOptions: [list[int, float], None] = None,
25
+ label: [str, None] = None,
23
26
  placeholder: [str, None] = None,
24
27
  maxValue: [float, int, None] = None,
25
28
  minValue: [float, int, None] = None,
@@ -30,6 +33,7 @@ class props(ApiValidator):
30
33
  precision: [int, None] = None,
31
34
  notationDisplay: [str, None] = None,
32
35
  unit: [str, None] = None,
36
+ unitPlacement: [str, None] = None,
33
37
  views: [list[str], None] = None,
34
38
  legendNotation: [str, None] = None,
35
39
  legendPrecision: [int, None] = None,
@@ -38,7 +42,6 @@ class props(ApiValidator):
38
42
  legendMaxLabel: [str, None] = None,
39
43
  icon: [str, None] = None,
40
44
  trailingZeros: [bool, None] = None,
41
- unitPlacement: [str, None] = None,
42
45
  locale: [str, None] = None,
43
46
  fallbackValue: [str, None] = None,
44
47
  draggable: [bool, None] = None,
@@ -59,6 +62,7 @@ class props(ApiValidator):
59
62
  * `"selector"`: Select options from a set
60
63
  * `"date"`: Select a date and/or time
61
64
  * `"media"`: View various media formats
65
+ * `"coordinate"`: A coordinate input field
62
66
  * **`help`**: `[str]` = `None` &rarr; The help text to display.
63
67
  * **`display`**: `[bool]` = `None` &rarr; Whether or not the prop will be displayed.
64
68
  * **`variant`**: `[str]` = `None` &rarr; The variant of the prop.
@@ -76,9 +80,11 @@ class props(ApiValidator):
76
80
  * `"slider"`: A range of values along a bar, from which users may select a single value
77
81
  * `"icon"`: A fixed numerical value presented alongside a corresponding icon.
78
82
  * `"iconCompact"`: Similar to `"icon"`, but designed in a compact format for appropriate rendering within a draggable pad.
83
+ * `"incslider"`: A range of values along a bar, from which users may select a single value, with a predefined set of options.
79
84
  * When **`type`** == `"selector"`:
80
85
  * `"checkbox"`: Select one or more items from a set of checkboxes
81
- * `"combobox"`: A dropdown with a search bar that allows users to filter options when typing
86
+ * `"combobox"`: A dropdown with a search bar allowing users to filter and select a single option by typing
87
+ * `"comboboxMulti"`: A dropdown with a search bar, enabling users to filter and select multiple options. Selected items are displayed as tags within the input field.
82
88
  * `"dropdown"`: Show multiple options that appear when the element is clicked
83
89
  * `"nested"`: Select one or more options from a set of nested checkboxes
84
90
  * `"radio"`: Select one option from a set of mutually exclusive options
@@ -95,38 +101,66 @@ class props(ApiValidator):
95
101
  * When **`type`** == `"media"`:
96
102
  * `"picture"`: Show a PNG or JPG image
97
103
  * `"video"`: Display a YouTube, Vimeo, or Dailymotion video clip
104
+ * When **`type`** == `"coordinate"`:
105
+ * `"latLngInput"`: A latitude and longitude input field
106
+ * `"latLngMap"`: A clickable map to select a latitude and longitude
107
+ * `"latLngPath"`: A clickable map to select a path of latitude and longitude points
108
+ * **`container`**: `[str]` = `"vertical"` | `"none"` &rarr;
109
+ * Specifies the type of prop container by selecting from predefined styles.
110
+ * **Accepted Values**:
111
+ * `"vertical"`: A vertical layout where the prop `name` appears at the top inside the container.
112
+ * `"horizontal"`: A horizontal layout where the prop `name` is on the left, followed by the actionable prop on the right.
113
+ * `"titled"`: Similar to the vertical container but without a background color, removing the embossed appearance of the prop.
114
+ * `"untitled"`: A slim container version without the prop `name` or `unit` label.
115
+ * `"none"`: Removes the prop container entirely, disabling the display of the prop `name`, `help` button and `unit` label. Only the actionable prop is displayed.
116
+ * **Notes**:
117
+ * This attribute applies to all props except the `"icon"` and `"iconCompact"` variants of the `"num"` prop.
118
+ * If left unspecified (i.e., `None`), the default is `"none"` for `"head"` props, and `"vertical"` for all others. As stated, the `"icon"` and `"iconCompact"` variants of the `"num"` prop are always set to `"none"`, regardless of this attribute.
119
+ * When the container is set to `"none"`, the `style` prop used at the `"item"` level of the `layout` becomes ineffective.
98
120
  * **`enabled`**: `[bool]` = `True` &rarr; Whether or not the prop will be enabled.
99
- * **Note**: This attribute is applicable to all props except `"head"` props.
121
+ * **Note**: This attribute applies to all props except `"head"` props.
100
122
  * **`apiCommand`**: `[str]` = `None` &rarr; The name of the API command to trigger.
101
123
  * **Note**: If `None`, no `apiCommand` is triggered.
102
- * **Note**: This attribute is applicable to all props except `"head"` props.
124
+ * **Note**: This attribute applies to all props except `"head"` props.
103
125
  * **`apiCommandKeys`**: `[list[str]]` = `None` &rarr;
104
126
  * The root API keys to pass to your `execute_command` function if an `apiCommand` is provided.
105
127
  * **Note**: If `None`, all API keys are passed to your `execute_command`.
106
- * **Note**: This attribute is applicable to all props except `"head"` props.
128
+ * **Note**: This attribute applies to all props except `"head"` props.
107
129
  * **`icon`**: `[str]` = `None` &rarr; The icon to use for the prop.
108
130
  * **Notes**:
109
131
  * It must be a valid icon name from the [react-icons][] bundle, preceded by the abbreviated name of the icon library source.
110
- * This attribute is applicable exclusively to `"head"` props.
132
+ * This attribute applies exclusively to `"head"` props.
111
133
  * **`options`**: `[dict]` = `None` &rarr;
134
+ * The options to be displayed on the UI element mapped to their display properties.
112
135
  * **Notes**:
113
136
  * Only options provided here are valid for the prop value
114
- * This attribute is applicable exclusively to `"selector"` props
137
+ * This attribute applies to only `"selector"` props
138
+ * **`numVisibleTags`**: `[int]` = `None` &rarr;
139
+ * The maximum number of tags visible in a `"comboboxMulti"` variant of a `"selector"` prop when it is not focused.
140
+ * **Notes**:
141
+ * If `None`, all tags will be displayed
142
+ * This attribute applies exclusively to `"selector"` props using the `"comboboxMulti"` variant
143
+ * **`valueOptions`**: `[list[int|float]]` = `None` &rarr;
144
+ * **Notes**:
145
+ * Only valueOptions provided here can be selected for the prop value
146
+ * This attribute applies to `"num"` props with the `"incslider"` variant.
147
+ * **`label`**: `[str]` = `None` &rarr; The label to display above the input field when the prop is focused.
148
+ * **Note**: This attribute applies to `"num"`, `"text"`, and `"coordinate"` props.
115
149
  * **`placeholder`**: `[str]` = `None` &rarr; The placeholder text to display.
116
- * **Note**: This attribute is applicable exclusively to `"text"` props.
150
+ * **Note**: This attribute applies exclusively to `"text"` props.
117
151
  * **`maxValue`**: `[float | int]` = `None` &rarr; The maximum value for the prop.
118
- * **Note**: This attribute is applicable exclusively to `"num"` props.
152
+ * **Note**: This attribute applies exclusively to `"num"` props.
119
153
  * **`minValue`**: `[float | int]` = `None` &rarr; The minimum value for the prop.
120
- * **Note**: This attribute is applicable exclusively to `"num"` props.
154
+ * **Note**: This attribute applies exclusively to `"num"` props.
121
155
  * **`maxRows`**: `[int]` = `None` &rarr;
122
156
  * The maximum number of rows to show for a `"textarea"` variant.
123
- * **Note**: This attribute is applicable exclusively to `"text"` props.
157
+ * **Note**: This attribute applies exclusively to `"text"` props.
124
158
  * **`minRows`**: `[int]` = `None` &rarr;
125
159
  * The minimum number of rows to show for a `"textarea"` variant.
126
- * **Note**: This attribute is applicable exclusively to `"text"` props.
160
+ * **Note**: This attribute applies exclusively to `"text"` props.
127
161
  * **`rows`**: `[int]` = `None` &rarr;
128
162
  * The fixed number of rows to show for a `"textarea"` variant.
129
- * **Note**: This attribute is applicable exclusively to `"text"` props.
163
+ * **Note**: This attribute applies exclusively to `"text"` props.
130
164
  * **`views`**: `[list[str]]` &rarr;
131
165
  * The available time units for the represented date and/or time.
132
166
  * **Default Value**:
@@ -151,33 +185,33 @@ class props(ApiValidator):
151
185
  * `"seconds"`: The seconds view
152
186
  * **Notes**:
153
187
  * The views will be presented in the order specified in the `views` array.
154
- * This attribute is applicable exclusively to `"date"` props.
188
+ * This attribute applies exclusively to `"date"` props.
155
189
  * **`locale`**: `[str]` = `None` &rarr;
156
190
  * Format numeric values based on language and regional conventions.
157
191
  * **Notes**:
158
192
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.locale`.
159
- * This attribute is applicable exclusively to `"num"` props.
193
+ * This attribute applies exclusively to `"num"` props.
160
194
  * **See**: [Locale identifier][].
161
195
  * **`precision`**: `[int]` = `None` &rarr; The number of decimal places to display.
162
196
  * **Notes**:
163
197
  * Set the precision to `0` to attach an integer constraint.
164
198
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.precision`.
165
- * This attribute is applicable exclusively to `"num"` props.
199
+ * This attribute applies exclusively to `"num"` props.
166
200
  * **`trailingZeros`**: `[bool]` = `None` &rarr; If `True`, trailing zeros will be displayed.
167
201
  * **Notes**:
168
202
  * This ensures that all precision digits are shown. For example: `1.5` &rarr; `1.500` when precision is `3`.
169
203
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.trailingZeros`.
170
- * This attribute is applicable exclusively to `"num"` props.
204
+ * This attribute applies exclusively to `"num"` props.
171
205
  * **`fallbackValue`**: [str] = `None` &rarr; A value to show when the value is missing or invalid.
172
206
  * **Notes**:
173
207
  * This is only for display purposes as related to number formatting. It does not affect the actual value or any computations.
174
208
  * For example, if the value passed is `None`, the fallback value will be displayed instead.
175
209
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.fallbackValue`.
176
- * This attribute is applicable exclusively to `"num"` props.
210
+ * This attribute applies exclusively to `"num"` props.
177
211
  * **`unit`**: `[str]` = `None` &rarr; The unit to use for the prop.
178
212
  * **Notes**:
179
213
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.unit`.
180
- * This attribute is applicable exclusively to `"num"` props.
214
+ * This attribute applies exclusively to `"num"` props.
181
215
  * **`unitPlacement`**: `[str]` = `None` &rarr; The position of the `unit` symbol relative to the value.
182
216
  * **Accepted Values**:
183
217
  * `"after"`: The `unit` appears after the value.
@@ -186,22 +220,23 @@ class props(ApiValidator):
186
220
  * `"beforeWithSpace"`: The unit is placed before the value, with a space in between.
187
221
  * **Notes**:
188
222
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.unitPlacement`.
189
- * This attribute is applicable exclusively to `"num"` props.
223
+ * This attribute applies exclusively to `"num"` props.
190
224
  * **`notation`**: `[str]` = `"standard"` &rarr; The formatting style of a numeric value.
191
225
  * **Accepted Values**:
192
226
  * `"standard"`: Plain number formatting
193
227
  * `"compact"`: Resembles the [metric prefix][] system
194
228
  * `"scientific"`: [Scientific notation][]
195
229
  * `"engineering"`: [Engineering notation][]
230
+ * `"precision"`: Emulates the [Number.prototype.toPrecision][] method
196
231
  * **Notes**:
197
232
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.notation`.
198
- * This attribute is applicable exclusively to `"num"` props.
233
+ * This attribute applies exclusively to `"num"` props.
199
234
  * **`notationDisplay`**: `[str]` = `"e+"` | `"short"` &rarr; Further customize the formatting within the selected `notation`.
200
235
  * **Accepted Values**:
201
236
  * When **`notation`** == `"compact"`:
202
237
  * `"short"`: Add symbols `K`, `M`, `B`, and `T` (in `"en-US"`) to denote thousands, millions, billions, and trillions, respectively.
203
238
  * `"long"`: Present numeric values with the informal suffix words `thousand`, `million`, `billion`, and `trillion` (in `"en-US"`).
204
- * When **`notation`** == `"scientific"` or `"engineering"`:
239
+ * When **`notation`** == `"scientific"`, `"engineering"` or `"precision"`:
205
240
  * `"e"`: Exponent symbol in lowercase as per the chosen `locale` identifier
206
241
  * `"e+"`: Similar to `"e"`, but with a plus sign for positive exponents.
207
242
  * `"E"`: Exponent symbol in uppercase as per the chosen `locale` identifier
@@ -213,24 +248,25 @@ class props(ApiValidator):
213
248
  * **Notes**:
214
249
  * No `notationDisplay` option is provided for a `"standard"` notation
215
250
  * The options `"short"` and `"long"` are only provided for the `"compact"` notation
216
- * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"` and `"engineering"` notations
251
+ * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"`, `"engineering"` and `"precision"` notations
217
252
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.notationDisplay`.
218
- * This attribute is applicable exclusively to `"num"` props.
253
+ * This attribute applies exclusively to `"num"` props.
219
254
  * **`legendPrecision`**: `[int]` = `None` &rarr;
220
255
  * The number of decimal places to display in the Map Legend.
221
256
  * **Notes**:
222
257
  * Set the precision to `0` to attach an integer constraint.
223
258
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.legendPrecision`.
224
- * This attribute is applicable exclusively to `"num"` props.
259
+ * This attribute applies exclusively to `"num"` props.
225
260
  * **`legendNotation`**: `[int]` = `"standard"` &rarr; The formatting style of a numeric value.
226
261
  * **Accepted Values**:
227
262
  * `"standard"`: Plain number formatting
228
263
  * `"compact"`: Resembles the [metric prefix][] system
229
264
  * `"scientific"`: [Scientific notation][]
230
265
  * `"engineering"`: [Engineering notation][]
266
+ * `"precision"`: Emulates the [Number.prototype.toPrecision][] method
231
267
  * **Notes**:
232
268
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.legendNotation`.
233
- * This attribute is applicable exclusively to `"num"` props.
269
+ * This attribute applies exclusively to `"num"` props.
234
270
  * **`legendNotationDisplay`**: `[str]` = `"e+"` | `"short"` &rarr; Further customize the formatting within the selected `legendNotation`.
235
271
  * **Accepted Values**:
236
272
  * `"short"`: Add symbols `K`, `M`, `B`, and `T` (in `"en-US"`) to denote thousands, millions, billions, and trillions, respectively.
@@ -244,26 +280,26 @@ class props(ApiValidator):
244
280
  * **Notes**:
245
281
  * No `legendNotationDisplay` option is provided for a `"standard"` legend notation
246
282
  * The options `"short"` and `"long"` are only provided for the `"compact"` legend notation
247
- * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"` and `"engineering"` legend notations
283
+ * The options `"e"`, `"e+"`, `"E"`, `"E+"`, `"x10^"`, and `"x10^+"` are provided for the `"scientific"`, `"engineering"` and `"precision"` notations
248
284
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.legendNotationDisplay`.
249
- * This attribute is applicable exclusively to `"num"` props.
285
+ * This attribute applies exclusively to `"num"` props.
250
286
  * **`legendMinLabel`**: `[str]` = `None` &rarr;
251
287
  * A custom and descriptive label in the Map Legend used to identify the lowest data point.
252
288
  * **Notes**:
253
289
  * Takes precedence over other formatting, except when used in a node cluster and the `cave_utils.api.maps.group` attribute is `True`. In this case, the min value within the node cluster is displayed.
254
290
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.legendMinLabel`.
255
- * This attribute is applicable exclusively to `"num"` props.
291
+ * This attribute applies exclusively to `"num"` props.
256
292
  * **`legendMaxLabel`**: `[str]` = `None` &rarr;
257
293
  * A custom and descriptive label in the Map Legend used to identify the highest data point.
258
294
  * **Notes**:
259
295
  * Takes precedence over other formatting, except when used in a node cluster and the `cave_utils.api.maps.group` attribute is `True`. In this case, the max value within the node cluster is displayed.
260
296
  * If left unspecified (i.e., `None`), it will default to `settings.defaults.legendMaxLabel`.
261
- * This attribute is applicable exclusively to `"num"` props.
297
+ * This attribute applies exclusively to `"num"` props.
262
298
  * **`draggable`**: `[bool]` = `None` &rarr;
263
299
  * If `True`, the prop will be rendered within the draggable global outputs pad.
264
300
  * **Notes**:
265
301
  * The prop's `variant` is enforced to `iconCompact` to accommodate it within the draggable pad.
266
- * This attribute is applicable exclusively to `"num"` props defined within `cave_utils.api.globalOutputs`.
302
+ * This attribute applies exclusively to `"num"` props defined within `cave_utils.api.globalOutputs`.
267
303
  * **`allowNone`**: `[bool]` = `False` &rarr;
268
304
  * Whether or not to allow `None` as a valid value for the prop. This is primarily used to help when validating `values` and `valueLists`.
269
305
  * **Notes**:
@@ -273,30 +309,40 @@ class props(ApiValidator):
273
309
  * See `nullColor` in: `/cave_utils/cave_utils/api/maps.html#colorByOptions`
274
310
  * For prop purposes: `None` values will be left blank.
275
311
  * If `False`, `None` will not be a valid value for the prop.
276
- * This attribute is applicable to all props except `"head"` props.
277
-
312
+ * This attribute applies to all props except `"head"` props.
278
313
 
314
+ [react-icons]: https://react-icons.github.io/react-icons/search
279
315
  [metric prefix]: https://en.wikipedia.org/wiki/Metric_prefix
280
316
  [Scientific notation]: https://en.wikipedia.org/wiki/Scientific_notation
281
317
  [Engineering notation]: https://en.wikipedia.org/wiki/Engineering_notation
318
+ [Number.prototype.toPrecision]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision
282
319
  """
283
320
  passed_values = {k: v for k, v in locals().items() if (v is not None) and k != "kwargs"}
284
321
  required_fields = ["name", "type"]
285
- optional_fields = ["help", "variant", "display"]
286
- if type != "head":
287
- optional_fields += ["enabled", "apiCommand", "apiCommandKeys", "allowNone"]
322
+ optional_fields = ["help", "variant", "display", "container"]
288
323
  if type == "head":
289
324
  if variant == "icon" or variant == "iconRow":
290
325
  required_fields += ["icon"]
326
+ else:
327
+ optional_fields += ["enabled", "apiCommand", "apiCommandKeys", "allowNone"]
328
+
291
329
  if type == "text":
292
- optional_fields += ["minRows", "maxRows", "rows"]
293
- if type == "num":
330
+ optional_fields += ["minRows", "maxRows", "rows", "label", "placeholder"]
331
+ elif type == "num":
294
332
  if variant == "slider":
295
333
  required_fields += ["maxValue", "minValue"]
334
+ elif variant == "incslider":
335
+ required_fields += ["valueOptions"]
296
336
  else:
297
337
  optional_fields += ["maxValue", "minValue"]
338
+ if variant is None or variant == "field":
339
+ optional_fields += [ "label", "placeholder"]
298
340
  if variant == "icon" or variant == "iconCompact":
299
341
  required_fields += ["icon"]
342
+ if notationDisplay:
343
+ required_fields += ["notation"]
344
+ if legendNotationDisplay:
345
+ required_fields += ["legendNotation"]
300
346
  optional_fields += [
301
347
  "unit",
302
348
  "notation",
@@ -311,14 +357,20 @@ class props(ApiValidator):
311
357
  "unitPlacement",
312
358
  "draggable",
313
359
  ]
314
- if type == "selector":
360
+ elif type == "selector":
315
361
  required_fields += ["options"]
316
362
  optional_fields += ["placeholder"]
317
- if type == "date":
363
+ if variant == "comboboxMulti":
364
+ optional_fields += ["numVisibleTags"]
365
+ elif type == "date":
318
366
  optional_fields += ["views"]
367
+ elif type == "coordinate":
368
+ optional_fields += ["label", "placeholder"]
369
+
319
370
  missing_required = pamda.difference(required_fields, list(passed_values.keys()))
320
371
  if len(missing_required) > 0:
321
372
  raise Exception(f"Missing required fields: {str(missing_required)}")
373
+
322
374
  for k, v in passed_values.items():
323
375
  if k not in required_fields + optional_fields:
324
376
  kwargs[k] = v
@@ -326,6 +378,7 @@ class props(ApiValidator):
326
378
  "compact": ["short", "long"],
327
379
  "scientific": ["e", "e+", "E", "E+", "x10^", "x10^+"],
328
380
  "engineering": ["e", "e+", "E", "E+", "x10^", "x10^+"],
381
+ "precision": ["e", "e+", "E", "E+", "x10^", "x10^+"],
329
382
  "standard": [],
330
383
  }
331
384
  notation = passed_values.get("notation", "standard")
@@ -339,17 +392,18 @@ class props(ApiValidator):
339
392
  return {
340
393
  "kwargs": kwargs,
341
394
  "accepted_values": {
342
- "type": ["head", "num", "toggle", "button", "text", "selector", "date", "media"],
395
+ "type": ["head", "num", "toggle", "button", "text", "selector", "date", "media", "coordinate"],
396
+ "container": ["vertical", "horizontal", "titled", "untitled", "none"],
343
397
  "views": view_options_dict.get(variant, []),
344
398
  "unitPlacement": ["after", "afterWithSpace", "before", "beforeWithSpace"],
345
- "notation": ["compact", "precision", "scientific", "engineering"],
399
+ "notation": ["standard", "compact", "scientific", "engineering", "precision"],
346
400
  "notationDisplay": notationDisplay_options_dict.get(notation, []),
347
- "legendNotation": ["compact", "precision", "scientific", "engineering"],
401
+ "legendNotation": ["standard", "compact", "scientific", "engineering", "precision"],
348
402
  "legendNotationDisplay": notationDisplay_options_dict.get(legendNotation, []),
349
403
  "variant": {
350
404
  "head": ["column", "row", "icon", "iconRow"],
351
405
  "text": ["single", "textarea"],
352
- "num": ["field", "slider", "icon", "iconCompact"],
406
+ "num": ["field", "slider", "icon", "iconCompact", "incslider"],
353
407
  "selector": [
354
408
  "dropdown",
355
409
  "checkbox",
@@ -362,6 +416,7 @@ class props(ApiValidator):
362
416
  ],
363
417
  "date": ["date", "time", "datetime"],
364
418
  "media": ["picture", "video"],
419
+ "coordinate": ["latLngInput", "latLngMap", "latLngPath"],
365
420
  }.get(type, []),
366
421
  },
367
422
  }
@@ -389,7 +444,7 @@ class props_options(ApiValidator):
389
444
  * **`path`**: `[list[str]]` = `None` &rarr; The path to an option.
390
445
  * **Notes**:
391
446
  * If `None`, the option will not be selectable
392
- * This attribute is applicable exclusively to `"nested"` props
447
+ * This attribute applies exclusively to `"nested"` props
393
448
  """
394
449
  variant = kwargs.get("variant")
395
450
  kwargs = {k: v for k, v in kwargs.items() if k != "variant"}
@@ -421,6 +476,7 @@ class layout(ApiValidator):
421
476
  itemId: [str, None] = None,
422
477
  column: [int, None] = None,
423
478
  row: [int, None] = None,
479
+ style: [dict, None] = None,
424
480
  **kwargs,
425
481
  ):
426
482
  """
@@ -433,25 +489,29 @@ class layout(ApiValidator):
433
489
  * **`numColumns`**: `[str | int]` = `"auto"` &rarr; The number of columns for the grid layout.
434
490
  * **Notes**:
435
491
  * If `"auto"`, the number of columns will be calculated based on the number of items.
436
- * This attribute is applicable exclusively to `"grid"` layouts.
492
+ * This attribute applies exclusively to `"grid"` layouts.
437
493
  * **`numRows`**: `[str | int]` = `"auto"` &rarr; The number of rows for the grid layout.
438
494
  * **Notes**:
439
495
  * If `"auto"`, the number of rows will be calculated based on the number of items.
440
- * This attribute is applicable exclusively to `"grid"` layouts.
496
+ * This attribute applies exclusively to `"grid"` layouts.
441
497
  * **`data`**: `[dict]` = `None` &rarr; The data for the layout.
442
- * **Note**: This attribute is applicable exclusively to `"grid"` layouts.
498
+ * **Note**: This attribute applies exclusively to `"grid"` layouts.
443
499
  * **`itemId`**: `[str]` = `None` &rarr; The id of the prop placed in the layout
444
- * **Note**: This attribute is applicable exclusively to `"item"` layouts.
500
+ * **Note**: This attribute applies exclusively to `"item"` layouts.
445
501
  * **`column`**: `[int]` = `None` &rarr; The column in which to place the prop in the current grid.
446
502
  * **`row`**: `[int]` = `None` &rarr; The row in which to place the prop in the current grid.
503
+ * **`style`**: `[dict | None]` = `None` &rarr; Provides an escape hatch for specifying CSS rules.
504
+ * **Note**: In `"item"` layouts, the `style` is applied to the root of the prop container, while in `"grid"` layouts, it targets the CSS Grid layout level.
447
505
  """
448
506
  passed_values = {k: v for k, v in locals().items() if (v is not None) and k != "kwargs"}
507
+ required_fields = ["type"]
508
+ optional_fields = ["style"]
449
509
  if type == "grid":
450
- required_fields = ["type", "data"]
451
- optional_fields = ["numColumns", "numRows", "column", "row"]
452
- if type == "item":
453
- required_fields = ["type", "itemId"]
454
- optional_fields = ["column", "row"]
510
+ required_fields += ["data"]
511
+ optional_fields += ["numColumns", "numRows", "column", "row"]
512
+ elif type == "item":
513
+ required_fields += ["itemId"]
514
+ optional_fields += ["column", "row"]
455
515
  missing_required = pamda.difference(required_fields, list(passed_values.keys()))
456
516
  if len(missing_required) > 0:
457
517
  raise Exception(f"Missing required fields: {str(missing_required)}")
@@ -467,9 +527,7 @@ class layout(ApiValidator):
467
527
  accepted_values["numColumns"] = ["auto"]
468
528
  return {
469
529
  "kwargs": kwargs,
470
- "accepted_values": {
471
- "type": ["grid", "item"],
472
- },
530
+ "accepted_values": accepted_values,
473
531
  }
474
532
 
475
533
  def __extend_spec__(self, **kwargs):
@@ -523,6 +581,7 @@ class values(ApiValidator):
523
581
  "selector": (list,),
524
582
  "date": (str,),
525
583
  "media": (str,),
584
+ "coordinate": (list,),
526
585
  }.get(prop_type, tuple())
527
586
  # Add None to acceptable types if allowed
528
587
  if prop_spec.get("allowNone", False):
@@ -551,6 +610,9 @@ class values(ApiValidator):
551
610
  )
552
611
  elif prop_type == "media":
553
612
  self.__check_url_valid__(prop_value, prepend_path=[prop_key])
613
+ elif prop_type == "coordinate":
614
+ coord_variant = prop_spec.get("variant", "latLngInput")
615
+ self.__check_coord_path_valid__(prop_value, coord_variant, prepend_path=[prop_key])
554
616
 
555
617
 
556
618
  @type_enforced.Enforcer
@@ -189,6 +189,17 @@ class ApiValidator:
189
189
  except:
190
190
  self.__error__(path=prepend_path, msg=msg)
191
191
 
192
+ # TODO: Implement a color value validator: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
193
+ def __check_color_string_valid__(self, color_string: str, prepend_path: list[str] = list()):
194
+ """
195
+ Validate a color string and if an issue is present, log an error
196
+ """
197
+ msg = "Invalid color string. Must be in a valid color format. See: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value"
198
+ try:
199
+ self.__check_rgba_string_valid__(rgba_string, prepend_path)
200
+ except:
201
+ self.__error__(path=prepend_path, msg=msg)
202
+
192
203
  def __check_pixel_string_valid__(self, pixel_string: str, prepend_path: list[str] = list()):
193
204
  """
194
205
  Validate a pixel string and if an issue is present, log an error
@@ -289,13 +300,21 @@ class ApiValidator:
289
300
  return True
290
301
 
291
302
  def __check_coord_path_valid__(
292
- self, coord_path: list[list[int, float]], prepend_path: list[str] = list()
303
+ self,
304
+ coord_path: list[list[int, float]],
305
+ coord_variant: str,
306
+ prepend_path: list[str] = list(),
293
307
  ):
294
308
  """
295
309
  Validate a coordinate path and if an issue is present, log an error
296
310
  """
297
311
  try:
298
- if len(coord_path) < 2:
312
+ if (
313
+ coord_variant == "latLngPath"
314
+ and len(coord_path) < 2
315
+ or coord_variant != "latLngPath"
316
+ and len(coord_path) > 1
317
+ ):
299
318
  self.__error__(path=prepend_path, msg="Invalid coordinate path")
300
319
  return
301
320
  for coord in coord_path:
@@ -38,20 +38,14 @@ class GeoUtils:
38
38
  * A list of dictionaries with additional properties for each path.
39
39
  * Note: The dictionaries must have the same length as the input lists.
40
40
  * Note: The dictionaries are imputed into the output GeoJSON as properties.
41
-
42
- Optional Arguments:
43
-
44
- * **`show_progress`**: `[bool]` &rarr;
45
- * If True, shows the progress of the calculations.
46
- * Default: False
47
- * **`filename`**: `[str, None]` &rarr;
41
+ * **`show_progress`**: `[bool]` = `False` &rarr;
42
+ * If `True`, shows the progress of the calculations.
43
+ * **`filename`**: `[str, None]` = `None` &rarr;
48
44
  * If provided, saves the output GeoJSON to the specified filename.
49
- * Default: None
50
45
 
51
46
  Returns:
52
47
 
53
48
  * **`output`**: `[dict]` &rarr; A GeoJSON dictionary with the shortest paths given the input data.
54
-
55
49
  """
56
50
  if not hasattr(geoGraph, "get_shortest_path"):
57
51
  raise ValueError("`geoGraph` must be a geoGraph object from scgraph")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cave_utils
3
- Version: 2.2.1
3
+ Version: 2.3.0
4
4
  Summary: Python wrapper for api use in the cave_app
5
5
  Author-email: Connor Makowski <conmak@mit.edu>
6
6
  Project-URL: Homepage, https://github.com/mit-cave/cave_utils
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
12
12
 
13
13
  [project]
14
14
  name = "cave_utils"
15
- version = "2.2.1"
15
+ version = "2.3.0"
16
16
  description = "Python wrapper for api use in the cave_app"
17
17
  authors = [
18
18
  {name="Connor Makowski", email="conmak@mit.edu"}
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = cave_utils
3
- version = 2.2.1
3
+ version = 2.3.0
4
4
  description_file = README.md
5
5
 
6
6
  [options]
File without changes
File without changes
File without changes
File without changes
File without changes