pymor.vectorarrays

Extended functionality for pyMOR vector arrays

Lbl


def Lbl(
    args:VAR_POSITIONAL, kwds:VAR_KEYWORD
):

Enum where members are also (and must be) strings


unlabel_dims


def unlabel_dims(
    obj
):
from sparse import COO, GCXS, SparseArray

XarrayVectorSpace


dataarray_coordinate_data


def dataarray_coordinate_data(
    da:DataArray, dim:str
)->tuple:

default_coordinate


def default_coordinate(
    dim:str='len', size:int | list[int] | tuple[int] | None=None
)->tuple:
da = DataArray(np.ones([1,2,3]), dims=['A', 'B', 'C'], coords={'A': ('A', [0]), 'C': ('C', [0, 1, 2])})
[dataarray_coordinate_data(da, dim) for dim in ['A', 'B', 'C']]
[(array([0]), {}), (array([0, 1]),), (array([0, 1, 2]), {})]
_
[(array([0]), {}), (array([0, 1]),), (array([0, 1, 2]), {})]

____


def ____(
    obj:None, shape:NoneType=None
):

____


def ____(
    obj:None, shape:NoneType=None
):

____


def ____(
    obj:None, shape:NoneType=None
):

____


def ____(
    obj:None, shape:NoneType=None
):

____


def ____(
    obj:None, shape:NoneType=None
):

____


def ____(
    obj:None, shape:NoneType=None
):

____


def ____(
    obj:None, shape:NoneType=None
):

validate_coord_data


def validate_coord_data(
    obj, shape:NoneType=None
)->dict:
validate_coord_data(da)
{'A': (array([0]), {}), 'B': (array([0, 1]),), 'C': (array([0, 1, 2]), {})}
validate_coord_data(da.coords)
{'A': (array([0]), {}), 'C': (array([0, 1, 2]), {})}
validate_coord_data({'A': (array([0]), {}), 'C': array([0, 1, 2])})
{'A': (array([0]), {}), 'C': (array([0, 1, 2]),)}
validate_coord_data('A')
{'A': (['A'],)}
validate_coord_data('A', 3)
{'A': (array([0, 1, 2]),)}
validate_coord_data(['A', 'B'], [3, 0])
{'A': (array([0, 1, 2]),), 'B': (['B'],)}
validate_coord_data(3)
{3: (array([0, 1, 2]),)}
validate_coord_data(None)
{}

coord_data_shape


def coord_data_shape(
    coord_data
):

make_coordinates


def make_coordinates(
    coord_data:dict
)->Coordinates:

XarrayVectorSpace


def XarrayVectorSpace(
    coord_data:xarray.core.coordinates.Coordinates | dict | xarray.core.dataarray.DataArray | str | None=None,
    name:str | None=None, attrs:dict | None=None,
    id:NoneType=None, # See `~pymor.vectorarrays.interface.VectorSpace.id`.
):

VectorSpace of XarrayVectorArrays.

“Empty” XarrayVectorSpace with no coordinates (used, for example, for operators whose range is a scalar):

space1 = XarrayVectorSpace()
space1
<xarray.DataArray 'XarrayVectorSpace' ()> Size: 8B
array(0.)

XarrayVectorSpace from dictionary of coordinates:

coords = {'A': [1, 2, 3]}
space1 = XarrayVectorSpace(coords)
space1
A(3)
<xarray.DataArray 'XarrayVectorSpace' (A: 3)> Size: 24B
array([0., 0., 0.])
Coordinates:
  * A        (A) int64 24B 1 2 3

The DataArray is created lazily:

vars(space1)
{'coord_data': {'A': ([1, 2, 3],)},
 '_name': None,
 'attrs': None,
 'id': None,
 'dims': ['A'],
 'ndim': 1,
 'shape': [3],
 'size': 3,
 '_locked': True,
 '_array': <xarray.DataArray 'XarrayVectorSpace' (A: 3)> Size: 24B
 array([0., 0., 0.])
 Coordinates:
   * A        (A) int64 24B 1 2 3}
space1.coords
Coordinates:
  * A        (A) int64 24B 1 2 3
vars(space1)
{'coord_data': {'A': ([1, 2, 3],)},
 '_name': None,
 'attrs': None,
 'id': None,
 'dims': ['A'],
 'ndim': 1,
 'shape': [3],
 'size': 3,
 '_locked': True,
 '_array': <xarray.DataArray 'XarrayVectorSpace' (A: 3)> Size: 24B
 array([0., 0., 0.])
 Coordinates:
   * A        (A) int64 24B 1 2 3,
 'coords': Coordinates:
   * A        (A) int64 24B 1 2 3}
coords = {'A': [1, 2, 3], 'B': ['a', 'b']}
space2 = XarrayVectorSpace(coords)
space2
A(3) ⛒ B(2)
<xarray.DataArray 'XarrayVectorSpace' (A: 3, B: 2)> Size: 48B
array([[0., 0.],
       [0., 0.],
       [0., 0.]])
Coordinates:
  * A        (A) int64 24B 1 2 3
  * B        (B) <U1 8B 'a' 'b'

From a list of coordinates with attributes:

coords = {'A': ([1, 2, 3], {'short_name': 'a'}), 'B': (['a', 'b'], {'short_name': 'b'})}
XarrayVectorSpace(coords)
A(3) ⛒ B(2)
<xarray.DataArray 'XarrayVectorSpace' (A: 3, B: 2)> Size: 48B
array([[0., 0.],
       [0., 0.],
       [0., 0.]])
Coordinates:
  * A        (A) int64 24B 1 2 3
  * B        (B) <U1 8B 'a' 'b'

From xarray Coordinates:

coords
{'A': ([1, 2, 3], {'short_name': 'a'}), 'B': (['a', 'b'], {'short_name': 'b'})}
coords = make_coordinates(coords)
XarrayVectorSpace(coords)
A(3) ⛒ B(2)
<xarray.DataArray 'XarrayVectorSpace' (A: 3, B: 2)> Size: 48B
array([[0., 0.],
       [0., 0.],
       [0., 0.]])
Coordinates:
  * A        (A) int64 24B 1 2 3
  * B        (B) <U1 8B 'a' 'b'

From DataArray:

da = DataArray(np.ones(coords.shape), coords=coords, name='C')
space = XarrayVectorSpace(da)
space
A(3) ⛒ B(2)
<xarray.DataArray 'C' (A: 3, B: 2)> Size: 48B
array([[0., 0.],
       [0., 0.],
       [0., 0.]])
Coordinates:
  * A        (A) int64 24B 1 2 3
  * B        (B) <U1 8B 'a' 'b'
space.dim
6
space.ndim
2

XarrayVectorSpace.rename


def rename(
    name
):
space = XarrayVectorSpace({'A': [1, 2], 'B': ['a', 'b', 'c']}, name='boo')
space
A(2) ⛒ B(3)
<xarray.DataArray 'boo' (A: 2, B: 3)> Size: 48B
array([[0., 0., 0.],
       [0., 0., 0.]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space.name
'boo'
space.rename('foo').name
'foo'

XarrayVectorSpace.__eq__


def __eq__(
    other
):

Return self==value.

space == space
True
space == space.rename('foo')
True

XarrayVectorSpace.__mul__


def __mul__(
    other
):
space2 = XarrayVectorSpace({'C': [1, 2], 'D': ['a', 'b', 'c']}, name='foo')
space3 = space * space2
space3
A(2) ⛒ B(3) ⛒ C(2) ⛒ D(3)
<xarray.DataArray 'foo' (A: 2, B: 3, C: 2, D: 3)> Size: 288B
array([[[[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]]],


       [[[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]]]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
  * C        (C) int64 16B 1 2
  * D        (D) <U1 12B 'a' 'b' 'c'
space3 == XarrayVectorSpace(space.coords + space2.coords)
True
space3.name
'foo'
space2 * space2 == space2
True

XarrayVectorArray


transpose_like


def transpose_like(
    a:ndarray, dims, new_dims
):
impl = XarrayVectorArrayImpl(
    np.arange(6).reshape(2, 3, 1), 
    space, 
    ['A', 'B', 'C'], 
    {"C": [0]}
)
impl
XarrayVectorArrayImpl(
    array([[[0, 1, 2], [3, 4, 5]]]),
    XarrayVectorSpace(coord_data={A: ([1, 2],), B: (['a', 'b', 'c'],)}, name='boo'),
    _data_dims=['C', 'A', 'B'],
    _extended_coord_data={C: ([0],)})
len(impl)
1
impl.array
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
# #|export
# #|hide
# def _abbreviate(s):
#     s = s.split('(')[0]
#     words = s.split()
#     if len(words) > 1: return ''.join(w[0].capitalize() for w in words)
#     return s[:2]
# #|export
# #|hide
# def _coords_str(coords, dims=None):
#     if not coords: return '{1}'
#     if dims is None: dims = list(coords)
#     return '{' + ' ⨉ '.join(f'{dim}({len(coords[dim])})' for dim in dims) + '}'
# #|export
# def _short_coords_str(coords, dims=None):
#     if not coords: return '{1}'
#     if dims is None: dims = list(coords)
#     return '{' + ' ⨉ '.join(f'{_abbreviate(dim)}({len(coords[dim])})' for dim in dims) + '}'
U = XarrayVectorArray(space, impl)
U
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.data
array([[[0, 1, 2],
        [3, 4, 5]]])
U.array
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.shape
(1, 2, 3)
U.coords
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.dims
['A', 'B']
U.extended_dims
['C']
U.extended_coord_data
{'C': ([0],)}

XarrayVectorSpace.from_data


def from_data(
    data, data_dims:NoneType=None, extended_coord_data:NoneType=None
):

Create a VectorArray with an extended dimension:

U = space.from_data(
    np.arange(6).reshape(2, 3, 1), 
    ['A', 'B', 'C'], 
    {"C": [0]}
)
U
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.data
array([[[0, 1, 2],
        [3, 4, 5]]])
U.array
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.shape
(1, 2, 3)
U.coords
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.dims
['A', 'B']
U.extended_dims
['C']
U.extended_coord_data
{'C': ([0],)}

Create a VectorArray with no extended dimension:

U = space.from_data(
    np.arange(6).reshape(2, 3),
    ['A', 'B'],
)
U
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.data
array([[0, 1, 2],
       [3, 4, 5]])
U.array
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.shape
(2, 3)
U.coords
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.dims
['A', 'B']
U.extended_dims
[]
U.extended_coord_data
{}

XarrayVectorSpace.from_numpy


def from_numpy(
    data:ndarray, extended_coord_data:dict | str | None=None, id:NoneType=None, ensure_copy:bool=False
)->XarrayVectorArray: # A vector array with data from the numpy array

Return an XarrayVectorArray in the vector space with data from the ndarray data.

space.from_numpy(np.arange(6))
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space.from_numpy(np.arange(6), {"C": [0]})
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

XarrayVectorSpace.from_xarray


def from_xarray(
    data:DataArray
)->XarrayVectorArray:

Return an XarrayVectorArray containing data from DataArray data.

da = space.from_numpy(np.arange(6)).array
da
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space.from_xarray(da)
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0, 1, 2],
       [3, 4, 5]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

An XarrayVectorArray from an array in space plus extended dimensions:

da = da * DataArray([1], coords={'C': [0]})
da
<xarray.DataArray (A: 2, B: 3, C: 1)> Size: 48B
array([[[0],
        [1],
        [2]],

       [[3],
        [4],
        [5]]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
  * C        (C) int64 8B 0
space.from_xarray(da)
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0, 1, 2],
        [3, 4, 5]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

XarrayVectorSpace.concatenate


def concatenate(
    arrays, dim
):

XarrayVectorSpace.array_from_fn


def array_from_fn(
    fn, extended_coords:dict | str | None=None, # Coordinates to extend vector space over
    reserve:int=0
)->XarrayVectorArray: # `XarrayVectorArray` with all elements equal to zero

Return XarrayVectorArray of null vectors in XarrayVectorSpace optionally extended to include supplied coordinates coords.


XarrayVectorSpace.zeros


def zeros(
    extended_coords:dict | None=None, # Coordinates to extend vector space over
    reserve:int=0
)->XarrayVectorArray: # `XarrayVectorArray` with all elements equal to zero

Return XarrayVectorArray of null vectors in XarrayVectorSpace optionally extended to include supplied coordinates coords.

space.zeros()
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0., 0., 0.],
       [0., 0., 0.]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space.zeros({'C': [0]})
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0., 0., 0.],
        [0., 0., 0.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

XarrayVectorSpace.ones


def ones(
    extended_coords:dict | None=None, # Coordinates to extend vector space over
    reserve:int=0
)->XarrayVectorArray: # `XarrayVectorArray` with all elements equal to one

Return XarrayVectorArray of vectors with each element equal to one in XarrayVectorSpace optionally extended to include supplied coordinates coords.

space.ones()
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[1., 1., 1.],
       [1., 1., 1.]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space.ones({'C': [0]})
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[1., 1., 1.],
        [1., 1., 1.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

XarrayVectorSpace.random


def random(
    extended_coords:NoneType=None,
    distribution:str='uniform', # Random distribution to use (`'uniform'`, `'normal'`).
    name:NoneType=None
)->XarrayVectorArray: # A random `XarrayVectorArray` in the vector space

Create a |VectorArray| of vectors with random entries.

Supported random distributions::

'uniform': Uniform distribution in half-open interval
           [`low`, `high`).
'normal':  Normal (Gaussian) distribution with mean
           `loc` and standard deviation `scale`.

Note that not all random distributions are necessarily implemented by all |VectorSpace| implementations.

from pymor.tools.random import new_rng
with new_rng(42):
    U = space.random()
U
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[0.77395605, 0.85859792, 0.09417735],
       [0.43887844, 0.69736803, 0.97562235]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
with new_rng(42):
    U = space.random({'C': [0]})
U
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0.77395605, 0.85859792, 0.09417735],
        [0.43887844, 0.69736803, 0.97562235]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

XarrayVectorSpace.__contains__


def __contains__(
    other
):
space in space2
False
space in space
True
U = space.zeros({'C': range(2)})
U
C(2) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 2, A: 2, B: 3)> Size: 96B
array([[[0., 0., 0.],
        [0., 0., 0.]],

       [[0., 0., 0.],
        [0., 0., 0.]]])
Coordinates:
  * C        (C) int64 16B 0 1
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U in space
True

XarrayVectorArray.array_labeled_as_source


def array_labeled_as_source(
    
):
U.array_labeled_as_source()
<xarray.DataArray (C: 2, A (source): 2, B (source): 3)> Size: 96B
array([[[0., 0., 0.],
        [0., 0., 0.]],

       [[0., 0., 0.],
        [0., 0., 0.]]])
Coordinates:
  * C           (C) int64 16B 0 1
  * A (source)  (A (source)) int64 16B 1 2
  * B (source)  (B (source)) <U1 12B 'a' 'b' 'c'

XarrayVectorArray.item


def item(
    
):

Return the single value stored in the array if there is only one value.

XarrayVectorSpace({'i': [0]}).ones().item()
1.0
# #|export
# @patch(as_prop=True)
# def dims(self:XarrayVectorArray): return self.array.dims
# #|export
# @patch
# def stacked_data(self:XarrayVectorArray):
#     return transpose_like(
#         self.data, self.array.dims, self.dims + self.extended_dims
#     ).reshape(
#         self.space.size, *(self.extended_shape or [1])
#     )

XarrayVectorArrayImpl.stacked_data


def stacked_data(
    
):
U
C(2) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 2, A: 2, B: 3)> Size: 96B
array([[[0., 0., 0.],
        [0., 0., 0.]],

       [[0., 0., 0.],
        [0., 0., 0.]]])
Coordinates:
  * C        (C) int64 16B 0 1
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U = space.zeros({'C': np.arange(2), 'D': np.arange(2)})
U.impl.stacked_data().shape
(6, 4)
U = space.zeros()
U.impl.stacked_data()
array([[0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.]])
U = space.zeros({'C': range(2)})
U.impl.stacked_data()
array([[0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.]])

VectorArray.to_numpy


def to_numpy(
    ensure_copy:bool=False, # If `False`, modifying the returned |NumPy array| might alter the original
|VectorArray|. If `True` always a copy of the array data is made.
):

Return (self.dim, len(self)) NumPy Array with the data stored in the array.

U.to_numpy().shape
(6, 2)

This gives the same result as for a dimension-6 NumpyVectorSpace:

NumpyVectorSpace(6).zeros(2).to_numpy().shape
(6, 2)
space.zeros(space2.coords).shape
(2, 3, 2, 3)
space.zeros(space2.coords).to_numpy().shape
(6, 6)
# #|export
# @patch
# def rename(
#     self:XarrayVectorArray,
#     new_name_or_name_dict=None,
#     **names,
# ):
#     """Rename the vector array and/or any of its dimensions."""
#     vec = self.space.rename(new_name_or_name_dict, **names).from_xarray(self.array.rename(new_name_or_name_dict, **names))
#     if isinstance(new_name_or_name_dict, str): vec.name = new_name_or_name_dict
#     return vec
# U.rename('baz', A='bar')
space
A(2) ⛒ B(3)
<xarray.DataArray 'boo' (A: 2, B: 3)> Size: 48B
array([[0., 0., 0.],
       [0., 0., 0.]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U = space.ones({'C': [0]})
U
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[1., 1., 1.],
        [1., 1., 1.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U.scal(2)
U.data
array([[[2., 2., 2.],
        [2., 2., 2.]]])
U * 1j
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 96B
array([[[0.+2.j, 0.+2.j, 0.+2.j],
        [0.+2.j, 0.+2.j, 0.+2.j]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 = space.ones({'C': [0]})
U1
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[1., 1., 1.],
        [1., 1., 1.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U2 = space.ones()
U2
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[1., 1., 1.],
       [1., 1., 1.]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1.axpy(2, U2)
U1
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[3., 3., 3.],
        [3., 3., 3.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 = space.ones({'C': [0]})
U1
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[1., 1., 1.],
        [1., 1., 1.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1.axpy(2, U1)
U1
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[3., 3., 3.],
        [3., 3., 3.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 = space.ones({'C': [0]})
U1
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[1., 1., 1.],
        [1., 1., 1.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 + U1
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[2., 2., 2.],
        [2., 2., 2.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U2 = space.ones()
U1 + U2
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[2., 2., 2.],
        [2., 2., 2.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'

XarrayVectorArray.__mul__


def __mul__(
    other
):
U1 = space.ones({'C': [0]})
da = DataArray(np.arange(3), {'B': U1.array.B})
da
<xarray.DataArray (B: 3)> Size: 24B
array([0, 1, 2])
Coordinates:
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 * da
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0., 1., 2.],
        [0., 1., 2.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space.ones() * space2.zeros()
∅ ⛒ A(2) ⛒ B(3) ⛒ C(2) ⛒ D(3)
<xarray.DataArray (A: 2, B: 3, C: 2, D: 3)> Size: 288B
array([[[[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]]],


       [[[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]],

        [[0., 0., 0.],
         [0., 0., 0.]]]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
  * C        (C) int64 16B 1 2
  * D        (D) <U1 12B 'a' 'b' 'c'
U1 = space.ones()
U1
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 48B
array([[1., 1., 1.],
       [1., 1., 1.]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U2 = XarrayVectorSpace(U1.array.B).from_numpy(np.arange(3), extended_coord_data={'C': [0]})
U2
C(1) ⛒ B(3)
<xarray.DataArray (C: 1, B: 3)> Size: 24B
array([[0, 1, 2]])
Coordinates:
  * C        (C) int64 8B 0
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 * U2
C(1) ⛒ A(2) ⛒ B(3)
<xarray.DataArray (C: 1, A: 2, B: 3)> Size: 48B
array([[[0., 1., 2.],
        [0., 1., 2.]]])
Coordinates:
  * C        (C) int64 8B 0
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
U1 * 1j
∅ ⛒ A(2) ⛒ B(3)
<xarray.DataArray (A: 2, B: 3)> Size: 96B
array([[0.+1.j, 0.+1.j, 0.+1.j],
       [0.+1.j, 0.+1.j, 0.+1.j]])
Coordinates:
  * A        (A) int64 16B 1 2
  * B        (B) <U1 12B 'a' 'b' 'c'
space = XarrayVectorSpace({'A': [1], 'B': ['a', 'b']}, name='boo')
space
A(1) ⛒ B(2)
<xarray.DataArray 'boo' (A: 1, B: 2)> Size: 16B
array([[0., 0.]])
Coordinates:
  * A        (A) int64 8B 1
  * B        (B) <U1 8B 'a' 'b'
U = space.ones({'C': range(2)}) + 1j * space.ones({'C': range(2)})
U.real
C(2) ⛒ A(1) ⛒ B(2)
<xarray.DataArray (C: 2, A: 1, B: 2)> Size: 32B
array([[[1., 1.]],

       [[1., 1.]]])
Coordinates:
  * C        (C) int64 16B 0 1
  * A        (A) int64 8B 1
  * B        (B) <U1 8B 'a' 'b'
U.imag
C(2) ⛒ A(1) ⛒ B(2)
<xarray.DataArray (C: 2, A: 1, B: 2)> Size: 32B
array([[[1., 1.]],

       [[1., 1.]]])
Coordinates:
  * C        (C) int64 16B 0 1
  * A        (A) int64 8B 1
  * B        (B) <U1 8B 'a' 'b'
U
C(2) ⛒ A(1) ⛒ B(2)
<xarray.DataArray (C: 2, A: 1, B: 2)> Size: 64B
array([[[1.+1.j, 1.+1.j]],

       [[1.+1.j, 1.+1.j]]])
Coordinates:
  * C        (C) int64 16B 0 1
  * A        (A) int64 8B 1
  * B        (B) <U1 8B 'a' 'b'
U.conj()
C(2) ⛒ A(1) ⛒ B(2)
<xarray.DataArray (C: 2, A: 1, B: 2)> Size: 64B
array([[[1.-1.j, 1.-1.j]],

       [[1.-1.j, 1.-1.j]]])
Coordinates:
  * C        (C) int64 16B 0 1
  * A        (A) int64 8B 1
  * B        (B) <U1 8B 'a' 'b'
U.reim
Part(2) ⛒ C(2) ⛒ A(1) ⛒ B(2)
<xarray.DataArray (Part: 2, C: 2, A: 1, B: 2)> Size: 64B
array([[[[1., 1.]],

        [[1., 1.]]],


       [[[1., 1.]],

        [[1., 1.]]]])
Coordinates:
  * Part     (Part) <U2 16B 'Re' 'Im'
  * C        (C) int64 16B 0 1
  * A        (A) int64 8B 1
  * B        (B) <U1 8B 'a' 'b'
# #|export
# def _plotly_automargin(plot, element):
#     plot.state['layout']['yaxis']['automargin'] = True
#     plot.state['layout']['xaxis']['automargin'] = True
# #|export
# def _delete(string, strings):
#     for s in strings: string = string.replace(s, '')
#     return string
# #|export
# def _set_scrubber_fractional_value(column, fraction): 
#     scrubber = column.objects[1].objects[0]
#     scrubber.value = round(scrubber.end * fraction)
# #|export
# def _scaled_loc(arr, fraction):
#     return arr[int(len(arr) * fraction)]

XarrayVectorArray.visualize


def visualize(
    slider_label_precision:int=2
):

Visualize the data contained in the XarrayVectorArray. Put the first dimension with numerical coordinates on the x axis, and include a scrubber if there is a second numerical dimension. Atomic velocity is prioritized to be on the x axis, time is prioritized to be on the scrubber. Put categorical dimensions in the legend. If the data are complex, add the real and imaginary parts as a categorical dimension. If there are no numerical dimensions, plot the categorical dimension(s) as a horizontal bar plot.

space = XarrayVectorSpace({'foo': ['aaaaaaaaaaaaaaaaaa', 'b', 'c']})
U1 = space.random(name='bar')
U2 = 1j * space.random(name='bar')
U3 = space.random({'baz': np.arange(5)}, name='bar')
U4 = 1j * space.random({'baz': np.arange(5)}, name='bar')
U5 = space.random({'baz': np.arange(5), 'bing': .000123456 * np.linspace(0, 5, 6)}, name='bar')
U1.visualize()

(U1 + U2).visualize()

U3.visualize(line_width=10)

U3.visualize(title='biz', markers=True, xaxis_range=(.5, 3), line_width=0)

(U3 + U4).visualize()

U5.visualize(slider_label_precision=5)