Coverage for install/scipp/core/variable.py: 65%
93 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-04-28 01:28 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-04-28 01:28 +0000
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
3# @author Matthew Andrew
4# ruff: noqa: E501
6from __future__ import annotations
8import warnings
9from contextlib import contextmanager
10from typing import Any, Iterable, Optional, Sequence, TypeVar, Union
12import numpy as _np
13from numpy.typing import ArrayLike
15from .._scipp import core as _cpp
16from ..typing import DTypeLike
17from ..units import default_unit
18from ._sizes import _parse_dims_shape_sizes
19from .cpp_classes import DType, Unit, Variable
21NumberOrVar = TypeVar('NumberOrVar', Union[int, float], Variable)
24def scalar(
25 value: Any,
26 *,
27 variance: Any = None,
28 unit: Union[Unit, str, None] = default_unit,
29 dtype: Optional[DTypeLike] = None,
30) -> Variable:
31 """Constructs a zero dimensional :class:`Variable` with a unit and optional
32 variance.
34 Parameters
35 ----------
36 value:
37 Initial value.
38 variance:
39 Optional, initial variance.
40 unit:
41 Optional, unit.
42 dtype: scipp.typing.DTypeLike
43 Optional, type of underlying data. By default,
44 the dtype is inferred from the `value` argument.
45 Cannot be specified for value types of
46 Dataset or DataArray.
48 Returns
49 -------
50 :
51 A scalar (zero-dimensional) Variable.
53 See Also
54 --------
55 scipp.array, scipp.empty, scipp.index, scipp.ones, scipp.zeros
57 Examples
58 --------
59 With deduced dtype and default unit:
61 >>> sc.scalar(3.14)
62 <scipp.Variable> () float64 [dimensionless] 3.14
64 >>> sc.scalar('a string')
65 <scipp.Variable> () string <no unit> "a string"
67 Or specifying a unit and dtype:
69 >>> sc.scalar(3.14, unit='m', dtype=int)
70 <scipp.Variable> () int64 [m] 3
72 Calling ``scalar`` with a list (or similar array-like object) will store that
73 object in a scalar variable and *not* create an array variable:
75 >>> sc.scalar([1, 2, 3])
76 <scipp.Variable> () PyObject <no unit> [1, 2, 3]
77 """
78 return _cpp.Variable(
79 dims=(), values=value, variances=variance, unit=unit, dtype=dtype
80 )
83def index(value: Any, *, dtype: Optional[DTypeLike] = None) -> Variable:
84 """Constructs a zero dimensional :class:`Variable` representing an index.
86 This is equivalent to calling :py:func:`scipp.scalar` with unit=None.
88 Parameters
89 ----------
90 value:
91 Initial value.
92 dtype: scipp.typing.DTypeLike
93 Optional, type of underlying data. By default,
94 the dtype is inferred from the `value` argument.
96 Returns
97 -------
98 :
99 A scalar (zero-dimensional) variable without unit.
101 See Also
102 --------
103 scipp.scalar, scipp.array
105 Examples
106 --------
108 >>> sc.index(123)
109 <scipp.Variable> () int64 <no unit> 123
110 """
111 return scalar(value=value, dtype=dtype, unit=None)
114def zeros(
115 *,
116 dims: Optional[Sequence[str]] = None,
117 shape: Optional[Sequence[int]] = None,
118 sizes: Optional[dict[str, int]] = None,
119 unit: Union[Unit, str, None] = default_unit,
120 dtype: DTypeLike = DType.float64,
121 with_variances: bool = False,
122) -> Variable:
123 """Constructs a :class:`Variable` with default initialized values with
124 given dimension labels and shape.
126 The dims and shape can also be specified using a `sizes` dict.
127 Optionally can add default initialized variances.
128 Only keyword arguments accepted.
130 Parameters
131 ----------
132 dims:
133 Optional (if sizes is specified), dimension labels.
134 shape:
135 Optional (if sizes is specified), dimension sizes.
136 sizes:
137 Optional, dimension label to size map.
138 unit:
139 Unit of contents.
140 dtype: scipp.typing.DTypeLike
141 Type of underlying data.
142 with_variances:
143 If True includes variances initialized to 0.
145 Returns
146 -------
147 :
148 A variable filled with 0's.
150 See Also
151 --------
152 scipp.array, scipp.empty, scipp.ones, scipp.scalar, scipp.zeros_like
154 Examples
155 --------
157 >>> sc.zeros(dims=['x'], shape=[4])
158 <scipp.Variable> (x: 4) float64 [dimensionless] [0, 0, 0, 0]
160 >>> sc.zeros(sizes={'x': 4})
161 <scipp.Variable> (x: 4) float64 [dimensionless] [0, 0, 0, 0]
163 >>> sc.zeros(sizes={'y': 3}, with_variances=True)
164 <scipp.Variable> (y: 3) float64 [dimensionless] [0, 0, 0] [0, 0, 0]
166 >>> sc.zeros(sizes={'z': 3}, unit='kg', dtype=int)
167 <scipp.Variable> (z: 3) int64 [kg] [0, 0, 0]
168 """
170 return _cpp.zeros(
171 **_parse_dims_shape_sizes(dims, shape, sizes),
172 unit=unit,
173 dtype=dtype,
174 with_variances=with_variances,
175 )
178def ones(
179 *,
180 dims: Optional[Sequence[str]] = None,
181 shape: Optional[Sequence[int]] = None,
182 sizes: Optional[dict[str, int]] = None,
183 unit: Union[Unit, str, None] = default_unit,
184 dtype: DTypeLike = DType.float64,
185 with_variances: bool = False,
186) -> Variable:
187 """Constructs a :class:`Variable` with values initialized to 1 with
188 given dimension labels and shape.
190 The dims and shape can also be specified using a `sizes` dict.
192 Parameters
193 ----------
194 dims:
195 Optional (if sizes is specified), dimension labels.
196 shape:
197 Optional (if sizes is specified), dimension sizes.
198 sizes:
199 Optional, dimension label to size map.
200 unit:
201 Unit of contents.
202 dtype: scipp.typing.DTypeLike
203 Type of underlying data.
204 with_variances:
205 If True includes variances initialized to 1.
207 Returns
208 -------
209 :
210 A variable filled with 1's.
212 See Also
213 --------
214 scipp.array, scipp.empty, scipp.ones_like, scipp.scalar, scipp.zeros
216 Examples
217 --------
219 >>> sc.ones(dims=['x'], shape=[4])
220 <scipp.Variable> (x: 4) float64 [dimensionless] [1, 1, 1, 1]
222 >>> sc.ones(sizes={'x': 4})
223 <scipp.Variable> (x: 4) float64 [dimensionless] [1, 1, 1, 1]
225 >>> sc.ones(sizes={'y': 3}, with_variances=True)
226 <scipp.Variable> (y: 3) float64 [dimensionless] [1, 1, 1] [1, 1, 1]
228 >>> sc.ones(sizes={'z': 3}, unit='kg', dtype=int)
229 <scipp.Variable> (z: 3) int64 [kg] [1, 1, 1]
230 """
231 return _cpp.ones(
232 **_parse_dims_shape_sizes(dims, shape, sizes),
233 unit=unit,
234 dtype=dtype,
235 with_variances=with_variances,
236 )
239def empty(
240 *,
241 dims: Optional[Sequence[str]] = None,
242 shape: Optional[Sequence[int]] = None,
243 sizes: Optional[dict[str, int]] = None,
244 unit: Union[Unit, str, None] = default_unit,
245 dtype: DTypeLike = DType.float64,
246 with_variances: bool = False,
247 aligned: bool = True,
248) -> Variable:
249 """Constructs a :class:`Variable` with uninitialized values with given
250 dimension labels and shape.
252 The dims and shape can also be specified using a `sizes` dict.
254 Warning
255 -------
256 'Uninitialized' means that values have undetermined values.
257 Reading elements before writing to them is undefined behavior.
258 Consider using :py:func:`scipp.zeros` unless you
259 know what you are doing and require maximum performance.
261 Parameters
262 ----------
263 dims:
264 Optional (if sizes is specified), dimension labels.
265 shape:
266 Optional (if sizes is specified), dimension sizes.
267 sizes:
268 Optional, dimension label to size map.
269 unit:
270 Unit of contents.
271 dtype: scipp.typing.DTypeLike
272 Type of underlying data.
273 with_variances:
274 If True includes uninitialized variances.
275 aligned:
276 Initial value for the alignment flag.
278 Returns
279 -------
280 :
281 A variable with uninitialized elements.
283 See Also
284 --------
285 scipp.array, scipp.empty_like, scipp.ones, scipp.scalar, scipp.zeros
287 Examples
288 --------
290 >>> var = sc.empty(dims=['x'], shape=[4])
291 >>> var[:] = sc.scalar(2.0) # initialize values before printing
292 >>> var
293 <scipp.Variable> (x: 4) float64 [dimensionless] [2, 2, 2, 2]
294 """
295 return _cpp.empty(
296 **_parse_dims_shape_sizes(dims, shape, sizes),
297 unit=unit,
298 dtype=dtype,
299 with_variances=with_variances,
300 aligned=aligned,
301 )
304def full(
305 *,
306 value: Any,
307 variance: Any = None,
308 dims: Optional[Sequence[str]] = None,
309 shape: Optional[Sequence[int]] = None,
310 sizes: Optional[dict[str, int]] = None,
311 unit: Union[Unit, str, None] = default_unit,
312 dtype: Optional[DTypeLike] = None,
313) -> Variable:
314 """Constructs a :class:`Variable` with values initialized to the specified
315 value with given dimension labels and shape.
317 The dims and shape can also be specified using a `sizes` dict.
319 Parameters
320 ----------
321 value:
322 The value to fill the Variable with.
323 variance:
324 The variance to fill the Variable with.
325 dims:
326 Optional (if sizes is specified), dimension labels.
327 shape:
328 Optional (if sizes is specified), dimension sizes.
329 sizes:
330 Optional, dimension label to size map.
331 unit:
332 Unit of contents.
333 dtype: scipp.typing.DTypeLike
334 Type of underlying data.
336 Returns
337 -------
338 :
339 A variable filled with given value.
341 See Also
342 --------
343 scipp.empty, scipp.full_like, scipp.ones, scipp.zeros
345 Examples
346 --------
348 >>> sc.full(value=2, dims=['x'], shape=[2])
349 <scipp.Variable> (x: 2) int64 [dimensionless] [2, 2]
351 >>> sc.full(value=2, sizes={'x': 2})
352 <scipp.Variable> (x: 2) int64 [dimensionless] [2, 2]
354 >>> sc.full(value=5, sizes={'y': 3, 'x': 2})
355 <scipp.Variable> (y: 3, x: 2) int64 [dimensionless] [5, 5, ..., 5, 5]
357 >>> sc.full(value=2.0, variance=0.1, sizes={'x': 3}, unit='s')
358 <scipp.Variable> (x: 3) float64 [s] [2, 2, 2] [0.1, 0.1, 0.1]
359 """
360 return (
361 scalar(value=value, variance=variance, unit=unit, dtype=dtype)
362 .broadcast(**_parse_dims_shape_sizes(dims, shape, sizes))
363 .copy()
364 )
367def vector(
368 value: Union[_np.ndarray, list], *, unit: Union[Unit, str, None] = default_unit
369) -> Variable:
370 """Constructs a zero dimensional :class:`Variable` holding a single length-3
371 vector.
373 Parameters
374 ----------
375 value:
376 Initial value, a list or 1-D numpy array.
377 unit:
378 Unit of contents.
380 Returns
381 -------
382 :
383 A scalar (zero-dimensional) variable of a vector.
385 See Also
386 --------
387 scipp.vectors:
388 Construct an array of vectors.
389 scipp.spatial.as_vectors:
390 Construct vectors from Scipp Variables
392 Examples
393 --------
395 >>> sc.vector(value=[1, 2, 3])
396 <scipp.Variable> () vector3 [dimensionless] (1, 2, 3)
398 >>> sc.vector(value=[4, 5, 6], unit='m')
399 <scipp.Variable> () vector3 [m] (4, 5, 6)
400 """
401 return vectors(dims=(), values=value, unit=unit)
404def vectors(
405 *,
406 dims: Sequence[str],
407 values: Union[_np.ndarray, list],
408 unit: Union[Unit, str, None] = default_unit,
409) -> Variable:
410 """Constructs a :class:`Variable` with given dimensions holding an array
411 of length-3 vectors.
413 Parameters
414 ----------
415 dims:
416 Dimension labels.
417 values:
418 Initial values.
419 unit:
420 Unit of contents.
422 Returns
423 -------
424 :
425 A variable of vectors with given values.
427 See Also
428 --------
429 scipp.vector:
430 Construct a single vector.
431 scipp.spatial.as_vectors:
432 Construct vectors from Scipp Variables
434 Examples
435 --------
437 >>> sc.vectors(dims=['x'], values=[[1, 2, 3]])
438 <scipp.Variable> (x: 1) vector3 [dimensionless] [(1, 2, 3)]
440 >>> var = sc.vectors(dims=['x'], values=[[1, 2, 3], [4, 5, 6]])
441 >>> var
442 <scipp.Variable> (x: 2) vector3 [dimensionless] [(1, 2, 3), (4, 5, 6)]
443 >>> var.values
444 array([[1., 2., 3.],
445 [4., 5., 6.]])
447 >>> sc.vectors(dims=['x'], values=[[1, 2, 3], [4, 5, 6]], unit='mm')
448 <scipp.Variable> (x: 2) vector3 [mm] [(1, 2, 3), (4, 5, 6)]
449 """
450 return _cpp.Variable(dims=dims, values=values, unit=unit, dtype=DType.vector3)
453def array(
454 *,
455 dims: Iterable[str],
456 values: ArrayLike,
457 variances: Optional[ArrayLike] = None,
458 unit: Union[Unit, str, None] = default_unit,
459 dtype: Optional[DTypeLike] = None,
460) -> Variable:
461 """Constructs a :class:`Variable` with given dimensions, containing given
462 values and optional variances.
464 Dimension and value shape must match.
465 Only keyword arguments accepted.
467 Parameters
468 ----------
469 dims:
470 Dimension labels
471 values: numpy.typing.ArrayLike
472 Initial values.
473 variances: numpy.typing.ArrayLike
474 Initial variances, must be same shape and size as values.
475 unit:
476 Unit of contents.
477 dtype: scipp.typing.DTypeLike
478 Type of underlying data. By default, inferred from `values` argument.
480 Returns
481 -------
482 :
483 A variable with the given values.
485 See Also
486 --------
487 scipp.empty, scipp.ones, scipp.scalar, scipp.zeros
489 Examples
490 --------
492 >>> sc.array(dims=['x'], values=[1, 2, 3])
493 <scipp.Variable> (x: 3) int64 [dimensionless] [1, 2, 3]
495 Multiple dimensions:
497 >>> sc.array(dims=['x', 'y'], values=[[1, 2, 3], [4, 5, 6]])
498 <scipp.Variable> (x: 2, y: 3) int64 [dimensionless] [1, 2, ..., 5, 6]
500 DType upcasting:
502 >>> sc.array(dims=['x'], values=[1, 2, 3.0])
503 <scipp.Variable> (x: 3) float64 [dimensionless] [1, 2, 3]
505 Manually specified dtype:
507 >>> sc.array(dims=['x'], values=[1, 2, 3], dtype=float)
508 <scipp.Variable> (x: 3) float64 [dimensionless] [1, 2, 3]
510 Set unit:
512 >>> sc.array(dims=['x'], values=[1, 2, 3], unit='m')
513 <scipp.Variable> (x: 3) int64 [m] [1, 2, 3]
515 Setting variances:
517 >>> sc.array(dims=['x'], values=[1.0, 2.0, 3.0], variances=[0.1, 0.2, 0.3])
518 <scipp.Variable> (x: 3) float64 [dimensionless] [1, 2, 3] [0.1, 0.2, 0.3]
519 """
520 return _cpp.Variable(
521 dims=dims, values=values, variances=variances, unit=unit, dtype=dtype
522 )
525def _expect_no_variances(args):
526 has_variances = [
527 key
528 for key, val in args.items()
529 if val is not None and val.variances is not None
530 ]
531 if has_variances:
532 raise _cpp.VariancesError(
533 'Arguments cannot have variances. ' f'Passed variances in {has_variances}'
534 )
537# Assumes that all arguments are Variable or None.
538def _ensure_same_unit(*, unit, args: dict):
539 if unit == default_unit:
540 units = {key: val.unit for key, val in args.items() if val is not None}
541 if len(set(units.values())) != 1:
542 raise _cpp.UnitError(
543 f'All units of the following arguments must be equal: {units}. '
544 'You can specify a unit explicitly with the `unit` argument.'
545 )
546 unit = next(iter(units.values()))
547 return {
548 key: _cpp.to_unit(val, unit, copy=False).value if val is not None else None
549 for key, val in args.items()
550 }, unit
553# Process arguments of arange, linspace, etc and return them as plain numbers or None.
554def _normalize_range_args(*, unit, **kwargs):
555 is_var = {
556 key: isinstance(val, _cpp.Variable)
557 for key, val in kwargs.items()
558 if val is not None
559 }
560 if any(is_var.values()):
561 if not all(is_var.values()):
562 arg_types = {key: type(val) for key, val in kwargs.items()}
563 raise TypeError(
564 'Either all of the following arguments or none have to '
565 f'be variables: {arg_types}'
566 )
567 _expect_no_variances(kwargs)
568 return _ensure_same_unit(unit=unit, args=kwargs)
569 return kwargs, unit
572def linspace(
573 dim: str,
574 start: NumberOrVar,
575 stop: NumberOrVar,
576 num: int,
577 *,
578 endpoint: bool = True,
579 unit: Union[Unit, str, None] = default_unit,
580 dtype: Optional[DTypeLike] = None,
581) -> Variable:
582 """Constructs a :class:`Variable` with `num` evenly spaced samples,
583 calculated over the interval `[start, stop]`.
585 Parameters
586 ----------
587 dim:
588 Dimension label.
589 start:
590 The starting value of the sequence.
591 stop:
592 The end value of the sequence.
593 num:
594 Number of samples to generate.
595 endpoint:
596 If True, `step` is the last returned value.
597 Otherwise, it is not included.
598 unit:
599 Unit of contents.
600 dtype: scipp.typing.DTypeLike
601 Type of underlying data. By default, inferred from `value` argument.
603 Returns
604 -------
605 :
606 A variable of evenly spaced values.
608 See Also
609 --------
610 scipp.arange, scipp.geomspace, scipp.logspace
612 Examples
613 --------
615 >>> sc.linspace('x', 2.0, 4.0, num=4)
616 <scipp.Variable> (x: 4) float64 [dimensionless] [2, 2.66667, 3.33333, 4]
617 >>> sc.linspace('x', 2.0, 4.0, num=4, endpoint=False)
618 <scipp.Variable> (x: 4) float64 [dimensionless] [2, 2.5, 3, 3.5]
620 >>> sc.linspace('x', 1.5, 3.0, num=4, unit='m')
621 <scipp.Variable> (x: 4) float64 [m] [1.5, 2, 2.5, 3]
622 """
623 range_args, unit = _normalize_range_args(unit=unit, start=start, stop=stop)
624 return array(
625 dims=[dim],
626 values=_np.linspace(**range_args, num=num, endpoint=endpoint),
627 unit=unit,
628 dtype=dtype,
629 )
632def geomspace(
633 dim: str,
634 start: NumberOrVar,
635 stop: NumberOrVar,
636 num: int,
637 *,
638 endpoint: bool = True,
639 unit: Union[Unit, str, None] = default_unit,
640 dtype: Optional[DTypeLike] = None,
641) -> Variable:
642 """Constructs a :class:`Variable` with values spaced evenly on a log scale
643 (a geometric progression).
645 This is similar to :py:func:`scipp.logspace`, but with endpoints specified
646 directly instead of as exponents.
647 Each output sample is a constant multiple of the previous.
649 Parameters
650 ----------
651 dim:
652 Dimension label.
653 start:
654 The starting value of the sequence.
655 stop:
656 The end value of the sequence.
657 num:
658 Number of samples to generate.
659 endpoint:
660 If True, `step` is the last returned value.
661 Otherwise, it is not included.
662 unit:
663 Unit of contents.
664 dtype: scipp.typing.DTypeLike
665 Type of underlying data. By default, inferred from `value` argument.
667 Returns
668 -------
669 :
670 A variable of evenly spaced values on a logscale.
672 See Also
673 --------
674 scipp.arange, scipp.linspace, scipp.logspace
676 Examples
677 --------
679 >>> sc.geomspace('x', 1.0, 1000.0, num=4)
680 <scipp.Variable> (x: 4) float64 [dimensionless] [1, 10, 100, 1000]
681 >>> sc.geomspace('x', 1.0, 1000.0, num=4, endpoint=False)
682 <scipp.Variable> (x: 4) float64 [dimensionless] [1, 5.62341, 31.6228, 177.828]
684 >>> sc.geomspace('x', 1.0, 100.0, num=3, unit='s')
685 <scipp.Variable> (x: 3) float64 [s] [1, 10, 100]
686 """
687 range_args, unit = _normalize_range_args(unit=unit, start=start, stop=stop)
688 return array(
689 dims=[dim],
690 values=_np.geomspace(**range_args, num=num, endpoint=endpoint),
691 unit=unit,
692 dtype=dtype,
693 )
696def logspace(
697 dim: str,
698 start: NumberOrVar,
699 stop: NumberOrVar,
700 num: int,
701 *,
702 endpoint: bool = True,
703 base: float = 10.0,
704 unit: Union[Unit, str, None] = default_unit,
705 dtype: Optional[DTypeLike] = None,
706) -> Variable:
707 """Constructs a :class:`Variable` with values spaced evenly on a log scale.
709 This is similar to :py:func:`scipp.geomspace`, but with endpoints specified
710 as exponents.
712 Parameters
713 ----------
714 dim:
715 Dimension label.
716 start:
717 The starting value of the sequence.
718 stop:
719 The end value of the sequence.
720 num:
721 Number of samples to generate.
722 base:
723 The base of the log space.
724 endpoint:
725 If True, `step` is the last returned value.
726 Otherwise, it is not included.
727 unit:
728 Unit of contents.
729 dtype: scipp.typing.DTypeLike
730 Type of underlying data. By default, inferred from `value` argument.
732 Returns
733 -------
734 :
735 A variable of evenly spaced values on a logscale.
737 See Also
738 --------
739 scipp.arange, scipp.geomspace, scipp.linspace
741 Examples
742 --------
744 >>> sc.logspace('x', 1, 4, num=4)
745 <scipp.Variable> (x: 4) float64 [dimensionless] [10, 100, 1000, 10000]
746 >>> sc.logspace('x', 1, 4, num=4, endpoint=False)
747 <scipp.Variable> (x: 4) float64 [dimensionless] [10, 56.2341, 316.228, 1778.28]
749 Set a different base:
751 >>> sc.logspace('x', 1, 4, num=4, base=2)
752 <scipp.Variable> (x: 4) float64 [dimensionless] [2, 4, 8, 16]
754 Set a unit:
756 >>> sc.logspace('x', 1, 3, num=3, unit='m')
757 <scipp.Variable> (x: 3) float64 [m] [10, 100, 1000]
758 """
759 # Passing unit='one' enforces that start and stop are dimensionless.
760 range_args, _ = _normalize_range_args(unit='one', start=start, stop=stop)
761 return array(
762 dims=[dim],
763 values=_np.logspace(**range_args, num=num, base=base, endpoint=endpoint),
764 unit=unit,
765 dtype=dtype,
766 )
769def arange(
770 dim: str,
771 start: Union[NumberOrVar, _np.datetime64, str],
772 stop: Optional[Union[NumberOrVar, _np.datetime64, str]] = None,
773 step: Optional[NumberOrVar] = None,
774 *,
775 unit: Union[Unit, str, None] = default_unit,
776 dtype: Optional[DTypeLike] = None,
777) -> Variable:
778 """Creates a :class:`Variable` with evenly spaced values within a given interval.
780 Values are generated within the half-open interval [start, stop).
781 In other words, the interval including start but excluding stop.
783 ``start``, ``stop``, and ``step`` may be given as plain values or as 0-D variables.
784 In the latter case this then implies the unit (the units of all arguments must be
785 identical), but a different unit-scale can still be requested with the ``unit``
786 argument.
788 When all the types or dtypes of the input arguments are the same, the output will
789 also have this dtype. This is different to :func:`numpy.arange` which will always
790 produce 64-bit (int64 or float64) outputs.
792 Warning
793 -------
794 The length of the output might not be numerically stable.
795 See :func:`numpy.arange`.
797 Parameters
798 ----------
799 dim:
800 Dimension label.
801 start:
802 Optional, the starting value of the sequence. Default=0.
803 stop:
804 End of interval. The interval does not include this value,
805 except in some (rare) cases where step is not an integer and
806 floating-point round-off can come into play.
807 step:
808 Spacing between values.
809 unit:
810 Unit of contents.
811 dtype: scipp.typing.DTypeLike
812 Type of underlying data. By default, inferred from `value` argument.
814 Returns
815 -------
816 :
817 A variable of evenly spaced values.
819 See Also
820 --------
821 scipp.geomspace, scipp.linspace, scipp.logspace
823 Examples
824 --------
826 >>> sc.arange('x', 4)
827 <scipp.Variable> (x: 4) int64 [dimensionless] [0, 1, 2, 3]
828 >>> sc.arange('x', 1, 5)
829 <scipp.Variable> (x: 4) int64 [dimensionless] [1, 2, 3, 4]
830 >>> sc.arange('x', 1, 5, 0.5)
831 <scipp.Variable> (x: 8) float64 [dimensionless] [1, 1.5, ..., 4, 4.5]
833 >>> sc.arange('x', 1, 5, unit='m')
834 <scipp.Variable> (x: 4) int64 [m] [1, 2, 3, 4]
836 Datetimes are also supported:
838 >>> sc.arange('t', '2000-01-01T01:00:00', '2000-01-01T01:01:30', 30 * sc.Unit('s'), dtype='datetime64')
839 <scipp.Variable> (t: 3) datetime64 [s] [2000-01-01T01:00:00, 2000-01-01T01:00:30, 2000-01-01T01:01:00]
841 Note that in this case the datetime ``start`` and ``stop`` strings implicitly
842 define the unit. The ``step`` must have the same unit.
843 """
844 if dtype == 'datetime64' and isinstance(start, str):
845 start = datetime(start)
846 stop = stop if stop is None else datetime(stop)
847 range_args, unit = _normalize_range_args(
848 unit=unit, start=start, stop=stop, step=step
849 )
850 args = [x for x in [start, stop, step] if x is not None]
851 types = [
852 x.values.dtype if isinstance(x, _cpp.Variable) else _np.asarray(x).dtype
853 for x in args
854 ]
855 if dtype is None:
856 candidates = set(types)
857 if len(candidates) == 1:
858 dtype = next(iter(candidates))
859 if dtype is not None and dtype != str('datetime64'):
860 numpy_dtype = str(dtype) if isinstance(dtype, DType) else dtype
861 else:
862 numpy_dtype = None
863 return array(
864 dims=[dim],
865 values=_np.arange(**range_args, dtype=numpy_dtype),
866 unit=unit,
867 dtype=dtype,
868 )
871@contextmanager
872def _timezone_warning_as_error():
873 with warnings.catch_warnings():
874 warnings.filterwarnings(
875 'error', category=DeprecationWarning, message='parsing timezone'
876 )
877 try:
878 yield
879 except DeprecationWarning:
880 raise ValueError(
881 'Parsing timezone aware datetimes is not supported'
882 ) from None
885def datetime(
886 value: Union[str, int, _np.datetime64],
887 *,
888 unit: Optional[Union[Unit, str, None]] = default_unit,
889) -> Variable:
890 """Constructs a zero dimensional :class:`Variable` with a dtype of datetime64.
892 Parameters
893 ----------
894 value:
896 - `str`: Interpret the string according to the ISO 8601 date time format.
897 - `int`: Number of time units (see argument ``unit``)
898 since Scipp's epoch (see :py:func:`scipp.epoch`).
899 - `np.datetime64`: Construct equivalent datetime of Scipp.
901 unit: Unit of the resulting datetime.
902 Can be deduced if ``value`` is a str or np.datetime64 but
903 is required if it is an int.
905 Returns
906 -------
907 :
908 A scalar variable containing a datetime.
910 See Also
911 --------
912 scipp.datetimes:
913 scipp.epoch:
914 Details in:
915 'Dates and Times' section in `Data Types <../../reference/dtype.rst>`_
917 Examples
918 --------
920 >>> sc.datetime('2021-01-10T14:16:15')
921 <scipp.Variable> () datetime64 [s] 2021-01-10T14:16:15
922 >>> sc.datetime('2021-01-10T14:16:15', unit='ns')
923 <scipp.Variable> () datetime64 [ns] 2021-01-10T14:16:15.000000000
924 >>> sc.datetime(1610288175, unit='s')
925 <scipp.Variable> () datetime64 [s] 2021-01-10T14:16:15
927 Get the current time:
929 >>> now = sc.datetime('now', unit='s')
930 """
931 if isinstance(value, str):
932 with _timezone_warning_as_error():
933 return scalar(_np.datetime64(value), unit=unit)
934 return scalar(value, unit=unit, dtype=_cpp.DType.datetime64)
937def datetimes(
938 *, dims, values: ArrayLike, unit: Optional[Union[Unit, str, None]] = default_unit
939) -> Variable:
940 """Constructs an array :class:`Variable` with a dtype of datetime64.
942 Parameters
943 ----------
944 dims:
945 Dimension labels
946 values: numpy.typing.ArrayLike
947 Numpy array or something that can be converted to a
948 Numpy array of datetimes.
949 unit:
950 Unit for the resulting Variable.
951 Can be deduced if ``values`` contains strings or np.datetime64's.
953 Returns
954 -------
955 :
956 An array variable containing a datetime.
958 See Also
959 --------
960 scipp.datetime:
961 scipp.epoch:
962 Details in:
963 'Dates and Times' section in `Data Types <../../reference/dtype.rst>`_
965 Examples
966 --------
968 >>> sc.datetimes(dims=['t'], values=['2021-01-10T01:23:45',
969 ... '2021-01-11T01:23:45'])
970 <scipp.Variable> (t: 2) datetime64 [s] [2021-01-10T01:23:45, 2021-01-11T01:23:45]
971 >>> sc.datetimes(dims=['t'], values=['2021-01-10T01:23:45',
972 ... '2021-01-11T01:23:45'], unit='h')
973 <scipp.Variable> (t: 2) datetime64 [h] [2021-01-10T01:00:00, 2021-01-11T01:00:00]
974 >>> sc.datetimes(dims=['t'], values=[0, 1610288175], unit='s')
975 <scipp.Variable> (t: 2) datetime64 [s] [1970-01-01T00:00:00, 2021-01-10T14:16:15]
976 """
977 np_unit_str = f'[{u}]' if (u := _cpp.to_numpy_time_string(unit)) else ''
978 with _timezone_warning_as_error():
979 return array(
980 dims=dims, values=_np.asarray(values, dtype=f'datetime64{np_unit_str}')
981 )
984def epoch(*, unit: Union[Unit, str]) -> Variable:
985 """Constructs a zero dimensional :class:`Variable` with a dtype of
986 datetime64 that contains Scipp's epoch.
988 Currently, the epoch of datetimes in Scipp is the Unix epoch 1970-01-01T00:00:00.
990 Parameters
991 ----------
992 unit:
993 Unit of the resulting Variable.
995 Returns
996 -------
997 :
998 A scalar variable containing the datetime of the epoch.
1000 See Also
1001 --------
1002 scipp.datetime:
1003 scipp.datetimes:
1004 Details in:
1005 'Dates and Times' section in `Data Types <../../reference/dtype.rst>`_
1007 Examples
1008 --------
1010 >>> sc.epoch(unit='s')
1011 <scipp.Variable> () datetime64 [s] 1970-01-01T00:00:00
1012 """
1013 return scalar(0, unit=unit, dtype=_cpp.DType.datetime64)