cave-utils 2.2.0b4__tar.gz → 2.2.1__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.0b4/cave_utils.egg-info → cave_utils-2.2.1}/PKG-INFO +1 -1
  2. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/__init__.py +2 -0
  3. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/__init__.py +2 -1
  4. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/appBar.py +1 -0
  5. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/extraKwargs.py +1 -0
  6. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/globalOutputs.py +1 -0
  7. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/groupedOutputs.py +18 -4
  8. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/mapFeatures.py +22 -7
  9. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/maps.py +1 -0
  10. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/pages.py +2 -1
  11. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/panes.py +1 -0
  12. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api/settings.py +2 -1
  13. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api_utils/general.py +9 -8
  14. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api_utils/validator.py +1 -0
  15. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api_utils/validator_utils.py +22 -17
  16. cave_utils-2.2.1/cave_utils/geo_utils.py +115 -0
  17. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/socket.py +0 -1
  18. {cave_utils-2.2.0b4 → cave_utils-2.2.1/cave_utils.egg-info}/PKG-INFO +1 -1
  19. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils.egg-info/SOURCES.txt +2 -0
  20. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/pyproject.toml +1 -1
  21. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/setup.cfg +1 -1
  22. cave_utils-2.2.1/test/test_geo_utils.py +17 -0
  23. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/LICENSE +0 -0
  24. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/NOTICE.md +0 -0
  25. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/README.md +0 -0
  26. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/api_utils/__init__.py +0 -0
  27. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/arguments.py +0 -0
  28. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/builders/__init__.py +0 -0
  29. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/builders/groups.py +0 -0
  30. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils/log.py +0 -0
  31. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils.egg-info/dependency_links.txt +0 -0
  32. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils.egg-info/requires.txt +0 -0
  33. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/cave_utils.egg-info/top_level.txt +0 -0
  34. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/test/test_arguments.py +0 -0
  35. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/test/test_builders_groups.py +0 -0
  36. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/test/test_import.py +0 -0
  37. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/test/test_log.py +0 -0
  38. {cave_utils-2.2.0b4 → cave_utils-2.2.1}/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.0b4
3
+ Version: 2.2.1
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
@@ -5,7 +5,9 @@ On the left hand side, you will find all available submodules, and their associa
5
5
 
6
6
  Click on a submodule to see the documentation for that submodule.
7
7
  """
8
+
8
9
  from .log import LogObject, LogHelper
9
10
  from .socket import Socket
10
11
  from .api_utils.validator import Validator
11
12
  from .arguments import Arguments
13
+ from .geo_utils import GeoUtils
@@ -11,6 +11,7 @@ Submodules (and their classes) are used to define the api at each level. You can
11
11
 
12
12
  See the left hand side for all available submodules.
13
13
  """
14
+
14
15
  from cave_utils.api_utils.validator_utils import *
15
16
  from cave_utils.api.extraKwargs import extraKwargs
16
17
  from cave_utils.api.settings import settings
@@ -97,7 +98,7 @@ class Root(ApiValidator):
97
98
  )
98
99
  # Special logic to add timeLength to kwargs
99
100
  # This is used to validate timeValues across the app
100
- kwargs["timeLength"] = pamda.path(["settings","time","timeLength"], self.data)
101
+ kwargs["timeLength"] = pamda.path(["settings", "time", "timeLength"], self.data)
101
102
  # Validate panes
102
103
  panes_data = self.data.get("panes")
103
104
  pane_validPaneIds = []
@@ -12,6 +12,7 @@ simultaneously.
12
12
  [predefined]: #appBar_data_star.spec
13
13
  [custom]: #appBar_data_star.spec
14
14
  """
15
+
15
16
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
16
17
  import type_enforced
17
18
 
@@ -2,6 +2,7 @@
2
2
  Optionally, pass special arguments to adjust some options related to
3
3
  how the CAVE API server handles data.
4
4
  """
5
+
5
6
  from cave_utils.api_utils.validator_utils import ApiValidator
6
7
  import type_enforced
7
8
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  These outputs should be general to the entire application and they can be compared across sessions.
4
4
  """
5
+
5
6
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
6
7
  from cave_utils.api_utils.general import props, values, layout
7
8
  import type_enforced
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Create grouped outputs for building generalized charts and tables.
3
3
  """
4
+
4
5
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
5
6
  import type_enforced
6
7
  from pamda import pamda
@@ -348,7 +349,14 @@ class groupedOutputs_groupings_star_levels_star(ApiValidator):
348
349
  """
349
350
 
350
351
  @staticmethod
351
- def spec(name: str, parent: [str, None] = None, ordering: [list, None] = None, orderWithParent: bool = True, coloring: [dict, None] = None, **kwargs):
352
+ def spec(
353
+ name: str,
354
+ parent: [str, None] = None,
355
+ ordering: [list, None] = None,
356
+ orderWithParent: bool = True,
357
+ coloring: [dict, None] = None,
358
+ **kwargs,
359
+ ):
352
360
  """
353
361
  Arguments:
354
362
 
@@ -387,15 +395,21 @@ class groupedOutputs_groupings_star_levels_star(ApiValidator):
387
395
  ordering = self.data.get("ordering")
388
396
  if ordering is not None:
389
397
  self.__check_subset_valid__(
390
- subset=ordering, valid_values=kwargs.get("acceptable_data_levels", {}).get(kwargs.get('CustomKeyValidatorFieldId'),[]), prepend_path=["ordering"]
398
+ subset=ordering,
399
+ valid_values=kwargs.get("acceptable_data_levels", {}).get(
400
+ kwargs.get("CustomKeyValidatorFieldId"), []
401
+ ),
402
+ prepend_path=["ordering"],
391
403
  )
392
404
 
393
405
  coloring = self.data.get("coloring")
394
406
  if coloring is not None:
395
407
  self.__check_subset_valid__(
396
408
  subset=list(coloring.keys()),
397
- valid_values=kwargs.get("acceptable_data_levels", {}).get(kwargs.get('CustomKeyValidatorFieldId'),[]),
409
+ valid_values=kwargs.get("acceptable_data_levels", {}).get(
410
+ kwargs.get("CustomKeyValidatorFieldId"), []
411
+ ),
398
412
  prepend_path=["coloring"],
399
413
  )
400
414
  for key, value in coloring.items():
401
- self.__check_rgba_string_valid__(rgba_string=value, prepend_path=['coloring', key])
415
+ self.__check_rgba_string_valid__(rgba_string=value, prepend_path=["coloring", key])
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Create visualizations for your map, including `arc`s, `node`s, and `geo`s, and customize their appearance.
3
3
  """
4
+
4
5
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
5
6
  from cave_utils.api_utils.general import props, valueLists, layout
6
7
  import type_enforced
@@ -155,10 +156,8 @@ class mapFeatures_data_star_data(ApiValidator):
155
156
  **kwargs,
156
157
  )
157
158
  # Validate that all lengths are the same
158
- lengths = [
159
- len(v) for k, v in location_data.items() if k not in ['timeValues', 'order']
160
- ] + [
161
- len(v) for k, v in valueLists_data.items() if k not in ['timeValues', 'order']
159
+ lengths = [len(v) for k, v in location_data.items() if k not in ["timeValues", "order"]] + [
160
+ len(v) for k, v in valueLists_data.items() if k not in ["timeValues", "order"]
162
161
  ]
163
162
  if len(set(lengths)) > 1:
164
163
  self.__error__(msg=f"location and valueLists keys must have the same length.", path=[])
@@ -193,10 +192,26 @@ class mapFeatures_data_star_data_location(ApiValidator):
193
192
  elif layer_type == "arc":
194
193
  if layer_geoJson is not None:
195
194
  required_keys = ["geoJsonValue"]
196
- optional_keys += ["path", "startLatitude", "startLongitude", "endLatitude", "endLongitude","startAltitude", "endAltitude"]
195
+ optional_keys += [
196
+ "path",
197
+ "startLatitude",
198
+ "startLongitude",
199
+ "endLatitude",
200
+ "endLongitude",
201
+ "startAltitude",
202
+ "endAltitude",
203
+ ]
197
204
  elif "path" in passed_keys:
198
205
  required_keys = ["path"]
199
- optional_keys += ["startLatitude", "startLongitude", "endLatitude", "endLongitude", "geoJsonValue","startAltitude", "endAltitude"]
206
+ optional_keys += [
207
+ "startLatitude",
208
+ "startLongitude",
209
+ "endLatitude",
210
+ "endLongitude",
211
+ "geoJsonValue",
212
+ "startAltitude",
213
+ "endAltitude",
214
+ ]
200
215
  else:
201
216
  required_keys = ["startLatitude", "startLongitude", "endLatitude", "endLongitude"]
202
217
  optional_keys += ["startAltitude", "endAltitude", "geoJsonValue", "path"]
@@ -215,7 +230,7 @@ class mapFeatures_data_star_data_location(ApiValidator):
215
230
  )
216
231
  continue
217
232
  if key == "geoJsonValue":
218
- if len(value_list)!=len(set(value_list)):
233
+ if len(value_list) != len(set(value_list)):
219
234
  self.__warn__(
220
235
  msg=f"`geoJsonValue` should be a list of unique values. Otherwise, the corresponding map feature may not render correctly.",
221
236
  path=[key],
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Configure the style and UI elements of your application's maps.
3
3
  """
4
+
4
5
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
5
6
  import type_enforced
6
7
 
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Configure your application's pages.
3
3
  """
4
+
4
5
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
5
6
  import type_enforced
6
7
 
@@ -137,7 +138,7 @@ class pages_data_star_pageLayout(ApiValidator):
137
138
  * **`maximized`**: `[bool]` = `False` &rarr; Whether or not the layout should be maximized.
138
139
  * **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.
139
140
  * **`defaultToZero`**: `[bool]` = `False` &rarr; Whether or not the chart should default missing values to zero.
140
-
141
+
141
142
  [area chart]: https://en.wikipedia.org/wiki/Area_chart
142
143
  [bar chart]: https://en.wikipedia.org/wiki/Bar_chart
143
144
  [stacked bar chart]: https://en.wikipedia.org/wiki/Bar_chart
@@ -3,6 +3,7 @@ Panes serve as main containers for UI controls such as toggles, text
3
3
  and number fields, sliders, etc. They can also contain buttons that
4
4
  facilitate interaction with actionable data.
5
5
  """
6
+
6
7
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
7
8
  from cave_utils.api_utils.general import props, values, layout
8
9
  import type_enforced
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Configure general settings for your application like the icons to use, how to sync data with the server, and more.
3
3
  """
4
+
4
5
  from cave_utils.api_utils.validator_utils import *
5
6
  import type_enforced
6
7
 
@@ -291,7 +292,7 @@ class settings_time(ApiValidator):
291
292
  * **Example**: `"Decade"`.
292
293
  """
293
294
  return {"kwargs": kwargs, "accepted_values": {}}
294
-
295
+
295
296
  def __extend_spec__(self, **kwargs):
296
297
  timeLength = self.data.get("timeLength")
297
298
  if timeLength < 1:
@@ -1,10 +1,10 @@
1
1
  """
2
2
  General API Spec items that are found in multiple places. This is not a key that should be passed as part of your `session_data`.
3
3
  """
4
+
4
5
  from pamda import pamda
5
6
  import type_enforced
6
7
  from cave_utils.api_utils.validator_utils import ApiValidator, CustomKeyValidator
7
- from typing import Literal
8
8
 
9
9
 
10
10
  @type_enforced.Enforcer
@@ -323,13 +323,13 @@ class props(ApiValidator):
323
323
  if k not in required_fields + optional_fields:
324
324
  kwargs[k] = v
325
325
  notationDisplay_options_dict = {
326
- 'compact': ['short', 'long'],
327
- 'scientific': ['e', 'e+', 'E', 'E+', 'x10^', 'x10^+'],
328
- 'engineering': ['e', 'e+', 'E', 'E+', 'x10^', 'x10^+'],
329
- 'standard': []
326
+ "compact": ["short", "long"],
327
+ "scientific": ["e", "e+", "E", "E+", "x10^", "x10^+"],
328
+ "engineering": ["e", "e+", "E", "E+", "x10^", "x10^+"],
329
+ "standard": [],
330
330
  }
331
- notation = passed_values.get('notation', 'standard')
332
- legendNotation = passed_values.get('legendNotation', 'standard')
331
+ notation = passed_values.get("notation", "standard")
332
+ legendNotation = passed_values.get("legendNotation", "standard")
333
333
  view_options_dict = {
334
334
  "date": ["year", "month", "day"],
335
335
  "time": ["hours", "minutes", "seconds"],
@@ -348,7 +348,7 @@ class props(ApiValidator):
348
348
  "legendNotationDisplay": notationDisplay_options_dict.get(legendNotation, []),
349
349
  "variant": {
350
350
  "head": ["column", "row", "icon", "iconRow"],
351
- "text": ["textarea"],
351
+ "text": ["single", "textarea"],
352
352
  "num": ["field", "slider", "icon", "iconCompact"],
353
353
  "selector": [
354
354
  "dropdown",
@@ -377,6 +377,7 @@ class props(ApiValidator):
377
377
  **kwargs,
378
378
  )
379
379
 
380
+
380
381
  @type_enforced.Enforcer
381
382
  class props_options(ApiValidator):
382
383
  @staticmethod
@@ -1,6 +1,7 @@
1
1
  """
2
2
  This module contains the primary Validator class that is used to validate your session_data against the API spec.
3
3
  """
4
+
4
5
  from cave_utils.api_utils.validator_utils import LogObject
5
6
  from cave_utils.api import Root
6
7
  import type_enforced
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Special utility functions to help in validating your data against the CAVE API. This is not a key that should be passed as part of your `session_data`.
3
3
  """
4
+
4
5
  from pamda import pamda
5
6
  import type_enforced
6
7
  import re, datetime
@@ -24,7 +25,7 @@ class ApiValidator:
24
25
  "accepted_values": {},
25
26
  }
26
27
 
27
- def __validate__(self, data:dict, log: LogObject, prepend_path: list[str] = list(), **kwargs):
28
+ def __validate__(self, data: dict, log: LogObject, prepend_path: list[str] = list(), **kwargs):
28
29
  """
29
30
  Run the API validation process for the passed data.
30
31
  """
@@ -39,7 +40,7 @@ class ApiValidator:
39
40
  if extra_kwargs != {}:
40
41
  self.__warn__(
41
42
  msg=f"Unknown Fields: {str(list(extra_kwargs.keys()))}",
42
- )
43
+ )
43
44
 
44
45
  except Exception as e:
45
46
  self.__error__(
@@ -77,7 +78,7 @@ class ApiValidator:
77
78
 
78
79
  # Additional core validations for generic terms like `order` and `timeValues`
79
80
  def __genericKeyValidation__(self, **kwargs):
80
- # Remove `timeValues` out prior to each level validation
81
+ # Remove `timeValues` out prior to each level validation
81
82
  data_timeValues = self.data.pop("timeValues", None)
82
83
  # Remove `order` out prior to each level validation
83
84
  data_order = self.data.pop("order", None)
@@ -85,20 +86,22 @@ class ApiValidator:
85
86
  timeLength = kwargs.get("timeLength")
86
87
  if timeLength is None:
87
88
  self.__error__(
88
- path=['timeValues'],
89
+ path=["timeValues"],
89
90
  msg="`settings.time.timeLength` must be specified to validate `timeValues`",
90
91
  )
91
92
  else:
92
93
  self.__timeValues_validation__(timeValues=data_timeValues, timeLength=timeLength)
93
94
  if data_order is not None:
94
95
  self.__order_validation__(order=data_order)
95
-
96
+
96
97
  @type_enforced.Enforcer
97
- def __order_validation__(self, order:dict[list[str,int]]):
98
+ def __order_validation__(self, order: dict[list[str, int]]):
98
99
  """
99
100
  Check that the ordering options are valid
100
101
  """
101
- orderable_data_keys = {key: list(value.keys()) for key, value in self.data.items() if isinstance(value, dict)}
102
+ orderable_data_keys = {
103
+ key: list(value.keys()) for key, value in self.data.items() if isinstance(value, dict)
104
+ }
102
105
  if self.__check_subset_valid__(
103
106
  subset=list(order.keys()),
104
107
  valid_values=list(orderable_data_keys.keys()),
@@ -110,15 +113,15 @@ class ApiValidator:
110
113
  valid_values=orderable_data_keys[order_key],
111
114
  prepend_path=["order", order_key],
112
115
  )
113
-
116
+
114
117
  @type_enforced.Enforcer
115
- def __timeValues_validation__(self, timeValues: [dict[dict],list[dict]], timeLength:int):
118
+ def __timeValues_validation__(self, timeValues: [dict[dict], list[dict]], timeLength: int):
116
119
  if len(timeValues) == 0:
117
120
  return
118
121
  if isinstance(timeValues, list):
119
122
  if len(timeValues) != timeLength:
120
123
  self.__error__(
121
- path=['timeValues'],
124
+ path=["timeValues"],
122
125
  msg=f"The length of `timeValues` (as a list) must be equal to `settings.time.timeLength` ({timeLength})",
123
126
  )
124
127
  return
@@ -126,22 +129,22 @@ class ApiValidator:
126
129
  keys = list(timeValues.keys())
127
130
  if not all(isinstance(key, int) for key in keys):
128
131
  self.__error__(
129
- path=['timeValues'],
132
+ path=["timeValues"],
130
133
  msg="`timeValues` (as a dict) keys must be integers",
131
134
  )
132
135
  return
133
- if not all(key >= 0 and key<timeLength for key in keys):
136
+ if not all(key >= 0 and key < timeLength for key in keys):
134
137
  self.__error__(
135
- path=['timeValues'],
138
+ path=["timeValues"],
136
139
  msg=f"`timeValues` (as a dict) keys must be integers between 0 and {timeLength-1} inclusive (1 minus the value at `settings.time.timeLength`)",
137
140
  )
138
141
  return
139
142
  timeValues = list(timeValues.values())
140
- timeValueTypes = {k:type(v) for k,v in timeValues[0].items()}
143
+ timeValueTypes = {k: type(v) for k, v in timeValues[0].items()}
141
144
  for timeValue in timeValues:
142
- if timeValueTypes != {k:type(v) for k,v in timeValue.items()}:
145
+ if timeValueTypes != {k: type(v) for k, v in timeValue.items()}:
143
146
  self.__error__(
144
- path=['timeValues'],
147
+ path=["timeValues"],
145
148
  msg="All timeValues must have the same keys and each key must have the same type",
146
149
  )
147
150
  return
@@ -285,7 +288,9 @@ class ApiValidator:
285
288
  return False
286
289
  return True
287
290
 
288
- def __check_coord_path_valid__(self, coord_path: list[list[int,float]], prepend_path: list[str] = list()):
291
+ def __check_coord_path_valid__(
292
+ self, coord_path: list[list[int, float]], prepend_path: list[str] = list()
293
+ ):
289
294
  """
290
295
  Validate a coordinate path and if an issue is present, log an error
291
296
  """
@@ -0,0 +1,115 @@
1
+ from pamda import pamda
2
+ import type_enforced
3
+
4
+
5
+ class GeoUtils:
6
+ @type_enforced.Enforcer
7
+ @staticmethod
8
+ def create_shortest_paths_geojson(
9
+ geoGraph,
10
+ ids: list[int, str],
11
+ origin_latitudes: list[int, float],
12
+ origin_longitudes: list[int, float],
13
+ destination_latitudes: list[int, float],
14
+ destination_longitudes: list[int, float],
15
+ additional_properties: [list[dict], None] = None,
16
+ show_progress: bool = False,
17
+ filename: [str, None] = None,
18
+ **kwargs,
19
+ ):
20
+ """
21
+ Creates a geoJson output with the shortest paths between a list of
22
+ origin and destination points.
23
+
24
+ Arguments:
25
+
26
+ * **`geoGraph`**: `[geoGraph]` &rarr; A geoGraph object from scgraph.
27
+ * **`ids`**: `[list[int, str]]` &rarr; A list of identifiers for each path.
28
+ * Note: These are imputed into the output GeoJSON as an id property.
29
+ * **`origin_latitudes`**: `[list[int, float]]` &rarr;
30
+ * A list of latitudes for the origin points.
31
+ * **`origin_longitudes`**: `[list[int, float]]` &rarr;
32
+ * A list of longitudes for the origin points.
33
+ * **`destination_latitudes`**: `[list[int, float]]` &rarr;
34
+ * A list of latitudes for the destination points.
35
+ * **`destination_longitudes`**: `[list[int, float]]` &rarr;
36
+ * A list of longitudes for the destination points.
37
+ * **`additional_properties`**: `[list[dict], None]` &rarr;
38
+ * A list of dictionaries with additional properties for each path.
39
+ * Note: The dictionaries must have the same length as the input lists.
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;
48
+ * If provided, saves the output GeoJSON to the specified filename.
49
+ * Default: None
50
+
51
+ Returns:
52
+
53
+ * **`output`**: `[dict]` &rarr; A GeoJSON dictionary with the shortest paths given the input data.
54
+
55
+ """
56
+ if not hasattr(geoGraph, "get_shortest_path"):
57
+ raise ValueError("`geoGraph` must be a geoGraph object from scgraph")
58
+ len_items = len(ids)
59
+ if additional_properties is None:
60
+ additional_properties = [{} for i in range(len_items)]
61
+ data = {
62
+ "ids": ids,
63
+ "origin_latitudes": origin_latitudes,
64
+ "origin_longitudes": origin_longitudes,
65
+ "destination_latitudes": destination_latitudes,
66
+ "destination_longitudes": destination_longitudes,
67
+ "additional_properties": additional_properties,
68
+ }
69
+ # Check that all the lists have at least one element
70
+ if len_items == 0:
71
+ raise ValueError("All input lists must have at least one element")
72
+ # Check that all the lists have the same length
73
+ if len(set(map(len, data.values()))) != 1:
74
+ raise ValueError("All input lists must have the same length")
75
+ features = []
76
+ # Iterate over the data and calculate the shortest path for
77
+ # each origin and destination pair
78
+ for idx, item in enumerate(pamda.pivot(data)):
79
+ item = dict(item)
80
+ shortest_path_output = geoGraph.get_shortest_path(
81
+ origin_node={
82
+ "latitude": item["origin_latitudes"],
83
+ "longitude": item["origin_longitudes"],
84
+ },
85
+ destination_node={
86
+ "latitude": item["destination_latitudes"],
87
+ "longitude": item["destination_longitudes"],
88
+ },
89
+ output_coordinate_path="list_of_lists_long_first",
90
+ **kwargs,
91
+ )
92
+ # Append the calculated path to the features list in GeoJSON format
93
+ features.append(
94
+ {
95
+ "type": "Feature",
96
+ "geometry": {
97
+ "type": "LineString",
98
+ "coordinates": shortest_path_output["coordinate_path"],
99
+ },
100
+ "properties": {
101
+ "id": item["ids"],
102
+ "length": shortest_path_output["length"],
103
+ **item["additional_properties"],
104
+ },
105
+ }
106
+ )
107
+ if show_progress:
108
+ print(f"Paths Calculated: {idx}/{len_items}", end="\r")
109
+ if show_progress:
110
+ print(f"Paths Calculated: {len_items}/{len_items}")
111
+ # Create the GeoJSON output
112
+ output = {"type": "FeatureCollection", "features": features}
113
+ if filename is not None:
114
+ pamda.write_json(data=output, filename=filename)
115
+ return output
@@ -1,7 +1,6 @@
1
1
  class Socket:
2
2
  def __init__(self, silent=False):
3
3
  self.silent = silent
4
- pass
5
4
 
6
5
  def broadcast(self, *args, **kwargs):
7
6
  if not self.silent:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cave_utils
3
- Version: 2.2.0b4
3
+ Version: 2.2.1
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
@@ -5,6 +5,7 @@ pyproject.toml
5
5
  setup.cfg
6
6
  cave_utils/__init__.py
7
7
  cave_utils/arguments.py
8
+ cave_utils/geo_utils.py
8
9
  cave_utils/log.py
9
10
  cave_utils/socket.py
10
11
  cave_utils.egg-info/PKG-INFO
@@ -30,6 +31,7 @@ cave_utils/builders/__init__.py
30
31
  cave_utils/builders/groups.py
31
32
  test/test_arguments.py
32
33
  test/test_builders_groups.py
34
+ test/test_geo_utils.py
33
35
  test/test_import.py
34
36
  test/test_log.py
35
37
  test/test_validator.py
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
12
12
 
13
13
  [project]
14
14
  name = "cave_utils"
15
- version = "2.2.0b4"
15
+ version = "2.2.1"
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.0b4
3
+ version = 2.2.1
4
4
  description_file = README.md
5
5
 
6
6
  [options]
@@ -0,0 +1,17 @@
1
+ from scgraph.geographs.marnet import marnet_geograph
2
+
3
+ from cave_utils import GeoUtils
4
+
5
+ count = 100
6
+ print("Creating 100 shortest paths geojson...")
7
+ out = GeoUtils.create_shortest_paths_geojson(
8
+ geoGraph=marnet_geograph,
9
+ ids=[str(i) for i in range(count)],
10
+ origin_latitudes=[0 + i / 4 for i in range(count)],
11
+ origin_longitudes=[0 + i / 4 for i in range(count)],
12
+ destination_latitudes=[0 - i / 4 for i in range(count)],
13
+ destination_longitudes=[0 - i / 4 for i in range(count)],
14
+ show_progress=True,
15
+ # filename="test.geojson"
16
+ )
17
+ print("Done!")
File without changes
File without changes
File without changes