sdata 1.5.0__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.
- sdata/__init__.py +140 -0
- sdata/base.py +684 -0
- sdata/contrib/__init__.py +0 -0
- sdata/contrib/piexif/__init__.py +12 -0
- sdata/contrib/piexif/_common.py +94 -0
- sdata/contrib/piexif/_dump.py +346 -0
- sdata/contrib/piexif/_exceptions.py +2 -0
- sdata/contrib/piexif/_exif.py +638 -0
- sdata/contrib/piexif/_insert.py +60 -0
- sdata/contrib/piexif/_load.py +270 -0
- sdata/contrib/piexif/_remove.py +56 -0
- sdata/contrib/piexif/_transplant.py +45 -0
- sdata/contrib/piexif/_webp.py +240 -0
- sdata/contrib/piexif/helper.py +66 -0
- sdata/contrib/ranger/__init__.py +8 -0
- sdata/contrib/ranger/collections/__init__.py +0 -0
- sdata/contrib/ranger/collections/rangebucketmap.py +346 -0
- sdata/contrib/ranger/collections/rangemap.py +396 -0
- sdata/contrib/ranger/collections/rangeset.py +483 -0
- sdata/contrib/ranger/range/__init__.py +0 -0
- sdata/contrib/ranger/range/cut.py +285 -0
- sdata/contrib/ranger/range/range.py +644 -0
- sdata/contrib/sobol_seq.py +394 -0
- sdata/contrib/sortedcontainers/LICENSE +13 -0
- sdata/contrib/sortedcontainers/__init__.py +74 -0
- sdata/contrib/sortedcontainers/sorteddict.py +789 -0
- sdata/contrib/sortedcontainers/sortedlist.py +2646 -0
- sdata/contrib/sortedcontainers/sortedset.py +733 -0
- sdata/contrib/sqlitedict.py +598 -0
- sdata/contrib/timeflake/__init__.py +40 -0
- sdata/contrib/timeflake/flake.py +69 -0
- sdata/contrib/timeflake/utils.py +47 -0
- sdata/deprecated/__init__.py +10 -0
- sdata/deprecated/data.py +1503 -0
- sdata/did/__init__.py +129 -0
- sdata/did/_http.py +67 -0
- sdata/did/base58btc.py +49 -0
- sdata/did/did_github.py +152 -0
- sdata/did/did_peer4.py +155 -0
- sdata/did/did_web.py +222 -0
- sdata/did/diddoc.py +75 -0
- sdata/did/ed25519.py +225 -0
- sdata/did/eddsa.py +107 -0
- sdata/did/errors.py +40 -0
- sdata/did/issue_vc.py +193 -0
- sdata/did/jose.py +126 -0
- sdata/did/keys.py +104 -0
- sdata/did/utils_didkey.py +161 -0
- sdata/did/verify_vp.py +158 -0
- sdata/doe.py +101 -0
- sdata/dtypes.py +510 -0
- sdata/experiments/__init__.py +331 -0
- sdata/experiments/blob0.py +131 -0
- sdata/experiments/file.py +42 -0
- sdata/experiments/filegroup.py +144 -0
- sdata/experiments/image_old.py +313 -0
- sdata/experiments/ks2.py +15 -0
- sdata/experiments/lapshear.py +8 -0
- sdata/experiments/material.py +7 -0
- sdata/experiments/parameters_deprecated.py +394 -0
- sdata/experiments/workbook.py +226 -0
- sdata/format.py +125 -0
- sdata/imagemeta.py +533 -0
- sdata/interactive.py +118 -0
- sdata/iolib/__init__.py +51 -0
- sdata/iolib/hashtree.py +264 -0
- sdata/iolib/json1sqlitestore.py +554 -0
- sdata/iolib/jsonsqlitestore.py +704 -0
- sdata/iolib/pud.py +242 -0
- sdata/iolib/reader.py +262 -0
- sdata/iolib/writer.py +419 -0
- sdata/metadata.py +882 -0
- sdata/parameter.py +414 -0
- sdata/schema.py +273 -0
- sdata/sclass/__init__.py +111 -0
- sdata/sclass/bfo_classes.py +362 -0
- sdata/sclass/blob.py +362 -0
- sdata/sclass/content.py +87 -0
- sdata/sclass/dataframe.py +1251 -0
- sdata/sclass/dataframegroup.py +187 -0
- sdata/sclass/dependency_graph.py +85 -0
- sdata/sclass/filereference.py +124 -0
- sdata/sclass/image.py +218 -0
- sdata/sclass/lazy_namespace.py +155 -0
- sdata/sclass/process.py +383 -0
- sdata/sclass/process_graph.py +221 -0
- sdata/sclass/zipfile.py +135 -0
- sdata/semantic.py +346 -0
- sdata/suuid.py +136 -0
- sdata/timestamp.py +336 -0
- sdata/tools.py +14 -0
- sdata/units.py +602 -0
- sdata/vocab.py +149 -0
- sdata-1.5.0.dist-info/METADATA +264 -0
- sdata-1.5.0.dist-info/RECORD +98 -0
- sdata-1.5.0.dist-info/WHEEL +5 -0
- sdata-1.5.0.dist-info/licenses/LICENSE-MIT +21 -0
- sdata-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Dict, Optional, Tuple, List, Union
|
|
3
|
+
import random
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Distribution:
|
|
7
|
+
def __init__(self, name: str, **params):
|
|
8
|
+
"""
|
|
9
|
+
Unified distribution object to encapsulate name and _parameter.
|
|
10
|
+
|
|
11
|
+
:param name: Name of the distribution (e.g., 'normal', 'uniform').
|
|
12
|
+
:param params: Parameters specific to the distribution.
|
|
13
|
+
"""
|
|
14
|
+
self.name = name
|
|
15
|
+
self.params = params
|
|
16
|
+
|
|
17
|
+
def to_dict(self) -> Dict:
|
|
18
|
+
"""Convert the distribution to a dictionary."""
|
|
19
|
+
return {
|
|
20
|
+
"name": self.name,
|
|
21
|
+
"params": self.params
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def from_dict(cls, data: Dict):
|
|
26
|
+
"""Create a Distribution instance from a dictionary."""
|
|
27
|
+
return cls(name=data["name"], **data.get("params", {}))
|
|
28
|
+
|
|
29
|
+
def generate_value(self, range: Union[Tuple[float, float], List[Union[int, str]]]) -> Union[float, int, str]:
|
|
30
|
+
"""
|
|
31
|
+
Generate a value based on the distribution within the specified range.
|
|
32
|
+
|
|
33
|
+
:param range: Tuple specifying the minimum and maximum values or a list of discrete options.
|
|
34
|
+
:return: Generated value.
|
|
35
|
+
"""
|
|
36
|
+
if isinstance(range, list):
|
|
37
|
+
return random.choice(range)
|
|
38
|
+
|
|
39
|
+
min_val, max_val = range
|
|
40
|
+
|
|
41
|
+
if self.name == "normal":
|
|
42
|
+
mean = self.params.get("mean", (min_val + max_val) / 2)
|
|
43
|
+
std_dev = self.params.get("std_dev", (max_val - min_val) / 6)
|
|
44
|
+
return max(min(random.gauss(mean, std_dev), max_val), min_val)
|
|
45
|
+
|
|
46
|
+
elif self.name == "truncated_gauss":
|
|
47
|
+
mean = self.params.get("mean", (min_val + max_val) / 2)
|
|
48
|
+
std_dev = self.params.get("std_dev", (max_val - min_val) / 6)
|
|
49
|
+
value = random.gauss(mean, std_dev)
|
|
50
|
+
while not (min_val <= value <= max_val):
|
|
51
|
+
value = random.gauss(mean, std_dev)
|
|
52
|
+
return value
|
|
53
|
+
|
|
54
|
+
elif self.name == "weibull":
|
|
55
|
+
scale = self.params.get("scale", (max_val - min_val) / 2)
|
|
56
|
+
shape = self.params.get("shape", 1.5)
|
|
57
|
+
return max(min(min_val + random.weibullvariate(scale, shape), max_val), min_val)
|
|
58
|
+
|
|
59
|
+
elif self.name == "uniform":
|
|
60
|
+
return random.uniform(min_val, max_val)
|
|
61
|
+
|
|
62
|
+
elif self.name == "exponential":
|
|
63
|
+
rate = self.params.get("rate", 1.0)
|
|
64
|
+
return max(min_val, min(random.expovariate(rate), max_val))
|
|
65
|
+
|
|
66
|
+
elif self.name == "lognormal":
|
|
67
|
+
mean = self.params.get("mean", (min_val + max_val) / 2)
|
|
68
|
+
sigma = self.params.get("sigma", (max_val - min_val) / 6)
|
|
69
|
+
return max(min_val, min(random.lognormvariate(mean, sigma), max_val))
|
|
70
|
+
|
|
71
|
+
elif self.name == "beta":
|
|
72
|
+
alpha = self.params.get("alpha", 2.0)
|
|
73
|
+
beta = self.params.get("beta", 5.0)
|
|
74
|
+
return min_val + (random.betavariate(alpha, beta) * (max_val - min_val))
|
|
75
|
+
|
|
76
|
+
elif self.name == "gamma":
|
|
77
|
+
shape = self.params.get("shape", 2.0)
|
|
78
|
+
scale = self.params.get("scale", 1.0)
|
|
79
|
+
return max(min_val, min(random.gammavariate(shape, scale), max_val))
|
|
80
|
+
|
|
81
|
+
elif self.name == "cauchy":
|
|
82
|
+
location = self.params.get("location", (min_val + max_val) / 2)
|
|
83
|
+
scale = self.params.get("scale", (max_val - min_val) / 4)
|
|
84
|
+
value = random.uniform(location - scale, location + scale)
|
|
85
|
+
return max(min_val, min(value, max_val))
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
raise ValueError(f"Unsupported distribution: {self.name}")
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class Parameter:
|
|
92
|
+
def __init__(self, name: str,
|
|
93
|
+
value: Union[float, int, str],
|
|
94
|
+
range: Optional[Union[Tuple[float, float], List[Union[int, str]]]] = None,
|
|
95
|
+
distribution: Optional[Distribution] = None,
|
|
96
|
+
type: Optional[str] = None,
|
|
97
|
+
description: Optional[str] = None,
|
|
98
|
+
discrete_values: Optional[List[Union[int, str]]] = None,
|
|
99
|
+
constant: Optional[bool] = False, ):
|
|
100
|
+
"""
|
|
101
|
+
Unified class for a parameter.
|
|
102
|
+
|
|
103
|
+
:param name: Name of the parameter
|
|
104
|
+
:param value: Value of the parameter
|
|
105
|
+
:param range: Range of the parameter (tuple or list, required for Variables or DiscreteVariables)
|
|
106
|
+
:param distribution: Distribution object for the parameter (optional)
|
|
107
|
+
:param type: Type of the parameter ("Constant", "Variable", or "DiscreteVariable")
|
|
108
|
+
:param description: Description of the parameter (optional)
|
|
109
|
+
:param discrete_values: Discrete values for "DiscreteVariable" type (optional)
|
|
110
|
+
"""
|
|
111
|
+
self.name = name
|
|
112
|
+
self.value = value
|
|
113
|
+
self.range = range
|
|
114
|
+
self.distribution = distribution
|
|
115
|
+
self.description = description
|
|
116
|
+
self.discrete_values = discrete_values
|
|
117
|
+
self.constant = constant
|
|
118
|
+
|
|
119
|
+
if type:
|
|
120
|
+
self.type = type
|
|
121
|
+
else:
|
|
122
|
+
if range is not None and isinstance(range, list):
|
|
123
|
+
self.type = "DiscreteVariable"
|
|
124
|
+
self.discrete_values = range
|
|
125
|
+
self.range = None
|
|
126
|
+
elif range is not None:
|
|
127
|
+
self.type = "Variable"
|
|
128
|
+
else:
|
|
129
|
+
self.type = "Constant"
|
|
130
|
+
|
|
131
|
+
if self.type == "Variable" and not self.distribution:
|
|
132
|
+
self.distribution = Distribution("uniform")
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def min(self):
|
|
136
|
+
if isinstance(self.range, (list, tuple)):
|
|
137
|
+
return self.range[0]
|
|
138
|
+
raise ValueError("min is only available for continuous ranges")
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def max(self):
|
|
142
|
+
if isinstance(self.range, (list, tuple)):
|
|
143
|
+
return self.range[1]
|
|
144
|
+
raise ValueError("max is only available for continuous ranges")
|
|
145
|
+
|
|
146
|
+
def set_type(self, new_type: str):
|
|
147
|
+
"""
|
|
148
|
+
Change the type of the parameter to "Constant", "Variable", or "DiscreteVariable".
|
|
149
|
+
|
|
150
|
+
:param new_type: The new type to set ("Constant", "Variable", or "DiscreteVariable").
|
|
151
|
+
"""
|
|
152
|
+
if new_type not in ["Constant", "Variable", "DiscreteVariable"]:
|
|
153
|
+
raise ValueError("Type must be 'Constant', 'Variable', or 'DiscreteVariable'")
|
|
154
|
+
|
|
155
|
+
self.type = new_type
|
|
156
|
+
|
|
157
|
+
if self.type == "Constant":
|
|
158
|
+
self.range = None
|
|
159
|
+
self.distribution = None
|
|
160
|
+
self.discrete_values = None
|
|
161
|
+
elif self.type == "Variable" and not self.distribution:
|
|
162
|
+
self.distribution = Distribution("uniform")
|
|
163
|
+
self.discrete_values = None
|
|
164
|
+
elif self.type == "DiscreteVariable":
|
|
165
|
+
self.range = None
|
|
166
|
+
|
|
167
|
+
def to_dict(self) -> Dict:
|
|
168
|
+
"""Convert the parameter to a dictionary."""
|
|
169
|
+
return {
|
|
170
|
+
"name": self.name,
|
|
171
|
+
"value": self.value,
|
|
172
|
+
"range": self.range,
|
|
173
|
+
"type": self.type,
|
|
174
|
+
"description": self.description,
|
|
175
|
+
"discrete_values": self.discrete_values,
|
|
176
|
+
"distribution": self.distribution.to_dict() if self.distribution else None
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@classmethod
|
|
180
|
+
def from_dict(cls, data: Dict):
|
|
181
|
+
"""Create a Parameter instance from a dictionary."""
|
|
182
|
+
distribution = None
|
|
183
|
+
if data.get("distribution"):
|
|
184
|
+
distribution = Distribution.from_dict(data["distribution"])
|
|
185
|
+
return cls(
|
|
186
|
+
name=data["name"],
|
|
187
|
+
value=data["value"],
|
|
188
|
+
range=data.get("range"),
|
|
189
|
+
distribution=distribution,
|
|
190
|
+
type=data.get("type"),
|
|
191
|
+
description=data.get("description"),
|
|
192
|
+
discrete_values=data.get("discrete_values")
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def to_json(self) -> str:
|
|
196
|
+
"""Serialize the parameter to a JSON string."""
|
|
197
|
+
return json.dumps(self.to_dict(), indent=4)
|
|
198
|
+
|
|
199
|
+
@classmethod
|
|
200
|
+
def from_json(cls, json_str: str):
|
|
201
|
+
"""Create a Parameter instance from a JSON string."""
|
|
202
|
+
data = json.loads(json_str)
|
|
203
|
+
return cls.from_dict(data)
|
|
204
|
+
|
|
205
|
+
def sample_value(self) -> Union[float, int, str]:
|
|
206
|
+
"""
|
|
207
|
+
Sample and update the value based on the defined distribution.
|
|
208
|
+
"""
|
|
209
|
+
if self.type == "Constant":
|
|
210
|
+
return self.value
|
|
211
|
+
elif self.type == "DiscreteVariable":
|
|
212
|
+
self.value = random.choice(self.discrete_values)
|
|
213
|
+
return self.value
|
|
214
|
+
self.value = self.distribution.generate_value(self.range)
|
|
215
|
+
return self.value
|
|
216
|
+
|
|
217
|
+
def sample_values(self, n: int) -> List[Union[float, int, str]]:
|
|
218
|
+
"""
|
|
219
|
+
Generate n sampled values based on the defined distribution.
|
|
220
|
+
"""
|
|
221
|
+
if self.type == "Constant":
|
|
222
|
+
return [self.value] * n
|
|
223
|
+
elif self.type == "DiscreteVariable":
|
|
224
|
+
return [random.choice(self.discrete_values) for _ in range(n)]
|
|
225
|
+
return [self.distribution.generate_value(self.range) for _ in range(n)]
|
|
226
|
+
|
|
227
|
+
def __repr__(self):
|
|
228
|
+
try:
|
|
229
|
+
value_range = f"{self.min:.2g},{self.max:.2g}"
|
|
230
|
+
except:
|
|
231
|
+
if self.discrete_values and len(self.discrete_values) > 4:
|
|
232
|
+
value_range = self.discrete_values[:4] + ["..."]
|
|
233
|
+
elif self.discrete_values:
|
|
234
|
+
value_range = self.discrete_values
|
|
235
|
+
else:
|
|
236
|
+
value_range = "None"
|
|
237
|
+
return f"({self.name}|{self.value}|[{value_range}]|{self.type})"
|
|
238
|
+
|
|
239
|
+
def __str__(self):
|
|
240
|
+
return self.__repr__()
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class ParameterSet:
|
|
244
|
+
def __init__(self, name=None):
|
|
245
|
+
"""
|
|
246
|
+
ParameterSet class to hold multiple _parameter in a dictionary.
|
|
247
|
+
"""
|
|
248
|
+
self.name = name or "N.N."
|
|
249
|
+
self._parameter = {}
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def parameters(self):
|
|
253
|
+
return self._parameter
|
|
254
|
+
|
|
255
|
+
def update(self, parameter_list):
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
"""
|
|
259
|
+
for parameter in parameter_list:
|
|
260
|
+
self._parameter[parameter.name] = parameter
|
|
261
|
+
|
|
262
|
+
def __getitem__(self, name):
|
|
263
|
+
return self.get(name)
|
|
264
|
+
|
|
265
|
+
def __contains__(self, item):
|
|
266
|
+
return item in self._parameter.keys()
|
|
267
|
+
|
|
268
|
+
def pop(self, pname):
|
|
269
|
+
try:
|
|
270
|
+
return self._parameter.pop(pname)
|
|
271
|
+
except KeyError as exp:
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
def __iter__(self):
|
|
275
|
+
for x in self._parameter.values():
|
|
276
|
+
yield x
|
|
277
|
+
|
|
278
|
+
def items(self):
|
|
279
|
+
"""
|
|
280
|
+
Provide a dict-like items view for parameters.
|
|
281
|
+
|
|
282
|
+
:return: Items view of parameters.
|
|
283
|
+
"""
|
|
284
|
+
return self._parameter.items()
|
|
285
|
+
|
|
286
|
+
def keys(self):
|
|
287
|
+
"""
|
|
288
|
+
Provide a dict-like keys view for parameters.
|
|
289
|
+
|
|
290
|
+
:return: Keys view of parameters.
|
|
291
|
+
"""
|
|
292
|
+
return self._parameter.keys()
|
|
293
|
+
|
|
294
|
+
def values(self):
|
|
295
|
+
"""
|
|
296
|
+
Provide a dict-like values view for parameters.
|
|
297
|
+
|
|
298
|
+
:return: Values view of parameters.
|
|
299
|
+
"""
|
|
300
|
+
return self._parameter.values()
|
|
301
|
+
|
|
302
|
+
def get(self, name, default=None):
|
|
303
|
+
if self._parameter.get(name) is not None:
|
|
304
|
+
return self._parameter.get(name)
|
|
305
|
+
else:
|
|
306
|
+
return default
|
|
307
|
+
def set(self, parameter: Parameter):
|
|
308
|
+
"""
|
|
309
|
+
Add a parameter to the set.
|
|
310
|
+
|
|
311
|
+
:param parameter: A Parameter object to add.
|
|
312
|
+
"""
|
|
313
|
+
self._parameter[parameter.name] = parameter
|
|
314
|
+
|
|
315
|
+
def add_parameters(self, parameter_list: List):
|
|
316
|
+
"""
|
|
317
|
+
Add a parameter to the set.
|
|
318
|
+
|
|
319
|
+
:param parameter: A Parameter object to add.
|
|
320
|
+
"""
|
|
321
|
+
for parameter in parameter_list:
|
|
322
|
+
self._parameter[parameter.name] = parameter
|
|
323
|
+
|
|
324
|
+
def to_dict(self) -> Dict[str, Dict]:
|
|
325
|
+
"""
|
|
326
|
+
Convert the entire parameter set to a dictionary.
|
|
327
|
+
|
|
328
|
+
:return: A dictionary of parameter dictionaries.
|
|
329
|
+
"""
|
|
330
|
+
d = {"name": self.name}
|
|
331
|
+
d["parameter"] = {pname: param.to_dict() for pname, param in self._parameter.items()}
|
|
332
|
+
return d
|
|
333
|
+
|
|
334
|
+
@classmethod
|
|
335
|
+
def from_dict(cls, data: Dict):
|
|
336
|
+
"""
|
|
337
|
+
Create a ParameterSet instance from a dictionary.
|
|
338
|
+
|
|
339
|
+
:param data: A dictionary containing parameter set data.
|
|
340
|
+
:return: A ParameterSet instance.
|
|
341
|
+
"""
|
|
342
|
+
instance = cls(name=data.get("name", "N.N."))
|
|
343
|
+
parameters = data.get("parameter", {})
|
|
344
|
+
for pname, param_data in parameters.items():
|
|
345
|
+
parameter = Parameter.from_dict(param_data) # Assuming Parameter has a from_dict method
|
|
346
|
+
instance.set(parameter)
|
|
347
|
+
return instance
|
|
348
|
+
|
|
349
|
+
def to_json(self) -> str:
|
|
350
|
+
"""
|
|
351
|
+
Convert the ParameterSet to a JSON string.
|
|
352
|
+
|
|
353
|
+
:return: JSON string representation of the ParameterSet.
|
|
354
|
+
"""
|
|
355
|
+
import json
|
|
356
|
+
return json.dumps(self.to_dict())
|
|
357
|
+
|
|
358
|
+
@classmethod
|
|
359
|
+
def from_json(cls, json_str: str):
|
|
360
|
+
"""
|
|
361
|
+
Create a ParameterSet instance from a JSON string.
|
|
362
|
+
|
|
363
|
+
:param json_str: JSON string containing parameter set data.
|
|
364
|
+
:return: A ParameterSet instance.
|
|
365
|
+
"""
|
|
366
|
+
import json
|
|
367
|
+
data = json.loads(json_str)
|
|
368
|
+
return cls.from_dict(data)
|
|
369
|
+
|
|
370
|
+
def print(self):
|
|
371
|
+
for pname in sorted(self._parameter.keys()):
|
|
372
|
+
print(self._parameter[pname])
|
|
373
|
+
|
|
374
|
+
def __repr__(self):
|
|
375
|
+
return f"ParameterSet({self.name}|{list(self._parameter.keys())})"
|
|
376
|
+
|
|
377
|
+
def __str__(self):
|
|
378
|
+
return self.__repr__()
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
if __name__ == '__main__':
|
|
382
|
+
# Example usage
|
|
383
|
+
param_constant = Parameter(name="constant_param", value=10.0, description="This is a constant parameter.")
|
|
384
|
+
param_variable = Parameter(name="variable_param", value=5.0, range=(0.0, 10.0),
|
|
385
|
+
description="This is a variable parameter.")
|
|
386
|
+
param_discrete = Parameter(name="discrete_param", value="a", range=["a", "b", "c"],
|
|
387
|
+
description="This is a discrete parameter.")
|
|
388
|
+
|
|
389
|
+
print(param_constant.to_json())
|
|
390
|
+
print(param_variable.to_json())
|
|
391
|
+
print(param_discrete.to_json())
|
|
392
|
+
|
|
393
|
+
print(param_variable.sample_values(5))
|
|
394
|
+
print(param_discrete.sample_values(5))
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# -*-coding: utf-8-*-
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger("sdata")
|
|
6
|
+
import collections
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import numpy as np
|
|
9
|
+
from sdata.timestamp import TimeStamp
|
|
10
|
+
import sdata
|
|
11
|
+
from sdata.deprecated.data import Data
|
|
12
|
+
from sdata.metadata import Metadata, Attribute
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import hashlib
|
|
16
|
+
import uuid
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Workbook(Data):
|
|
20
|
+
"""Workbook with Sheets
|
|
21
|
+
|
|
22
|
+
.. warning::
|
|
23
|
+
|
|
24
|
+
highly experimental"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, **kwargs):
|
|
27
|
+
"""Workbook with Sheets
|
|
28
|
+
|
|
29
|
+
:param name:
|
|
30
|
+
:param kwargs:
|
|
31
|
+
|
|
32
|
+
"""
|
|
33
|
+
Data.__init__(self, **kwargs)
|
|
34
|
+
|
|
35
|
+
self._sheets = collections.OrderedDict()
|
|
36
|
+
|
|
37
|
+
def create_sheet(self, name):
|
|
38
|
+
"""create a sheet to the Workbook
|
|
39
|
+
|
|
40
|
+
:param data:
|
|
41
|
+
:return: sdata.Data
|
|
42
|
+
"""
|
|
43
|
+
if not isinstance(name, str):
|
|
44
|
+
logger.error("{}.create_sheet: sheet name has to be a string!".format(self.__class__.__name__))
|
|
45
|
+
return
|
|
46
|
+
data = Data(name=name)
|
|
47
|
+
self._sheets[name] = data
|
|
48
|
+
return data
|
|
49
|
+
|
|
50
|
+
def add_sheet(self, data):
|
|
51
|
+
"""create a sheet to the Workbook
|
|
52
|
+
|
|
53
|
+
:param data:
|
|
54
|
+
:return: sdata.Data
|
|
55
|
+
"""
|
|
56
|
+
if isinstance(data, (Data, sdata.Data)):
|
|
57
|
+
self._sheets[data.name] = data
|
|
58
|
+
else:
|
|
59
|
+
logger.error("{}.add_sheet: need sdata.Data, got {}".format(self.__class__.__name__, type(data)))
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def sheetnames(self):
|
|
63
|
+
"""return sheet names of the workbook"""
|
|
64
|
+
return list(self._sheets.keys())
|
|
65
|
+
|
|
66
|
+
def get_sheet(self, name, default=None):
|
|
67
|
+
"""get Sheet from Workbook
|
|
68
|
+
|
|
69
|
+
:param name:
|
|
70
|
+
:return: sheet data
|
|
71
|
+
"""
|
|
72
|
+
return self._sheets.get(name, default)
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def sheets(self):
|
|
76
|
+
"""all sheets of the workbook"""
|
|
77
|
+
return list(self._sheets.values())
|
|
78
|
+
|
|
79
|
+
def __getitem__(self, name):
|
|
80
|
+
return self.get(name)
|
|
81
|
+
|
|
82
|
+
def __iter__(self):
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
:return:
|
|
86
|
+
"""
|
|
87
|
+
self._isheet = 0
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
def __next__(self):
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
:return:
|
|
94
|
+
"""
|
|
95
|
+
if self._isheet <= (len(self._sheets.keys()) - 1):
|
|
96
|
+
self._isheet += 1
|
|
97
|
+
return self._sheets.get(list(self._sheets.keys())[self._isheet - 1])
|
|
98
|
+
else:
|
|
99
|
+
raise StopIteration
|
|
100
|
+
|
|
101
|
+
def get(self, name, default=None):
|
|
102
|
+
if self.get_sheet(name) is not None:
|
|
103
|
+
return self.get_sheet(name)
|
|
104
|
+
else:
|
|
105
|
+
return default
|
|
106
|
+
|
|
107
|
+
def keys(self):
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
:return: list of Attribute names
|
|
111
|
+
"""
|
|
112
|
+
return list(self._sheets.keys())
|
|
113
|
+
|
|
114
|
+
def values(self):
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
:return: list of Attribute values
|
|
118
|
+
"""
|
|
119
|
+
return list(self._sheets.values())
|
|
120
|
+
|
|
121
|
+
def items(self):
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
:return: list of Attribute items (keys, values)
|
|
125
|
+
"""
|
|
126
|
+
return list(self._sheets.items())
|
|
127
|
+
|
|
128
|
+
def to_hdf5(self, filepath, **kwargs):
|
|
129
|
+
"""export sdata.Data to hdf5
|
|
130
|
+
|
|
131
|
+
:param filepath:
|
|
132
|
+
:param complib: default='zlib' ['zlib', 'lzo', 'bzip2', 'blosc', 'blosc:blosclz', 'blosc:lz4', 'blosc:lz4hc', 'blosc:snappy', 'blosc:zlib', 'blosc:zstd']
|
|
133
|
+
:param complevel: default=9 [0-9]
|
|
134
|
+
|
|
135
|
+
:return:
|
|
136
|
+
"""
|
|
137
|
+
if not isinstance(self.df, pd.DataFrame):
|
|
138
|
+
df = pd.DataFrame()
|
|
139
|
+
else:
|
|
140
|
+
df = self.df
|
|
141
|
+
kwargs["mode"] = "w"
|
|
142
|
+
if kwargs.get("complib") is None:
|
|
143
|
+
kwargs["complib"] = "zlib"
|
|
144
|
+
|
|
145
|
+
if kwargs.get("complevel") is None:
|
|
146
|
+
kwargs["complevel"] = 9
|
|
147
|
+
|
|
148
|
+
with pd.HDFStore(filepath, **kwargs) as hdf:
|
|
149
|
+
hdf.put('metadata', self.metadata.df, format='fixed', data_columns=True)
|
|
150
|
+
hdf.put('table', df, format='fixed', data_columns=True)
|
|
151
|
+
hdf.put('description', self.description_to_df(), format='fixed', data_columns=True)
|
|
152
|
+
|
|
153
|
+
for sheet in self.sheets:
|
|
154
|
+
if not isinstance(sheet.df, pd.DataFrame):
|
|
155
|
+
logger.warning("no df in sheet!")
|
|
156
|
+
df = pd.DataFrame()
|
|
157
|
+
else:
|
|
158
|
+
df = sheet.df
|
|
159
|
+
hdf.put(f'/sheets/uuid_{sheet.uuid}/metadata', sheet.metadata.df, format='fixed', data_columns=True)
|
|
160
|
+
hdf.put(f'/sheets/uuid_{sheet.uuid}/table', df, format='fixed', data_columns=True)
|
|
161
|
+
hdf.put(f'/sheets/uuid_{sheet.uuid}/description', sheet.description_to_df(), format='fixed',
|
|
162
|
+
data_columns=True)
|
|
163
|
+
|
|
164
|
+
@classmethod
|
|
165
|
+
def metadata_from_hdf5(cls, filepath, **kwargs):
|
|
166
|
+
"""import sdata.Data.Metadata from hdf5
|
|
167
|
+
|
|
168
|
+
:param filepath:
|
|
169
|
+
:return: sdata.Data
|
|
170
|
+
"""
|
|
171
|
+
if not os.path.exists:
|
|
172
|
+
logger.error("hdf5 file '{}' not available".format(filepath))
|
|
173
|
+
return
|
|
174
|
+
|
|
175
|
+
with pd.HDFStore(filepath, mode="r+") as hdf:
|
|
176
|
+
metadata_path = "/metadata".format(uuid)
|
|
177
|
+
df_metadata = hdf.get(metadata_path)
|
|
178
|
+
metadata = Metadata.from_dataframe(df_metadata)
|
|
179
|
+
return metadata
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def from_hdf5(cls, filepath, **kwargs):
|
|
183
|
+
"""import sdata.Data from hdf5
|
|
184
|
+
|
|
185
|
+
:param filepath:
|
|
186
|
+
:return: sdata.Data
|
|
187
|
+
"""
|
|
188
|
+
if not os.path.exists:
|
|
189
|
+
logger.error("hdf5 file '{}' not available".format(filepath))
|
|
190
|
+
return
|
|
191
|
+
|
|
192
|
+
def read_data(nodepath):
|
|
193
|
+
metadata_path = f"{nodepath}/metadata".format(uuid)
|
|
194
|
+
table_path = f"{nodepath}/table".format(uuid)
|
|
195
|
+
description_path = f"{nodepath}/description".format(uuid)
|
|
196
|
+
df_metadata = hdf.get(metadata_path)
|
|
197
|
+
# print(df_metadata)
|
|
198
|
+
df_table = hdf.get(table_path)
|
|
199
|
+
df_description = hdf.get(description_path)
|
|
200
|
+
metadata = Metadata.from_dataframe(df_metadata)
|
|
201
|
+
# logger.debug("hdf {}".format(metadata.get("!sdata_uuid").value))
|
|
202
|
+
sheetdata = Data(metadata=metadata, table=df_table)
|
|
203
|
+
sheetdata.metadata = metadata
|
|
204
|
+
sheetdata.description_from_df(df_description)
|
|
205
|
+
# print(sheetdata.df)
|
|
206
|
+
return sheetdata
|
|
207
|
+
|
|
208
|
+
with pd.HDFStore(filepath, mode="r+") as hdf:
|
|
209
|
+
metadata_path = "/metadata".format(uuid)
|
|
210
|
+
table_path = "/table".format(uuid)
|
|
211
|
+
description_path = "/description".format(uuid)
|
|
212
|
+
df_metadata = hdf.get(metadata_path)
|
|
213
|
+
df_table = hdf.get(table_path)
|
|
214
|
+
df_description = hdf.get(description_path)
|
|
215
|
+
metadata = Metadata.from_dataframe(df_metadata)
|
|
216
|
+
# logger.debug("hdf {}".format(metadata.get("!sdata_uuid").value))
|
|
217
|
+
wb = Workbook(metadata=metadata, table=df_table)
|
|
218
|
+
wb.metadata = metadata
|
|
219
|
+
wb.description_from_df(df_description)
|
|
220
|
+
s = hdf.get_node("/sheets")
|
|
221
|
+
for g in s._v_groups:
|
|
222
|
+
# print(g)
|
|
223
|
+
nodepath = f"/sheets/{g}"
|
|
224
|
+
sheetdata = read_data(nodepath)
|
|
225
|
+
wb.add_sheet(sheetdata)
|
|
226
|
+
return wb
|