vdata 0.3.1__tar.gz → 0.3.2__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.
- {vdata-0.3.1 → vdata-0.3.2}/PKG-INFO +2 -2
- {vdata-0.3.1 → vdata-0.3.2}/pyproject.toml +2 -2
- {vdata-0.3.1 → vdata-0.3.2}/vdata/__init__.py +5 -3
- {vdata-0.3.1 → vdata-0.3.2}/vdata/_typing.py +1 -3
- {vdata-0.3.1 → vdata-0.3.2}/vdata/anndata_proxy/anndata.py +50 -25
- {vdata-0.3.1 → vdata-0.3.2}/vdata/anndata_proxy/containers.py +16 -11
- {vdata-0.3.1 → vdata-0.3.2}/vdata/array_view.py +2 -2
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/__init__.py +6 -4
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_indexing.py +2 -2
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/time.py +4 -4
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/base.py +8 -12
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/layers.py +6 -3
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/obs.py +1 -2
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/var.py +9 -9
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/view.py +5 -5
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/concatenate.py +2 -3
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/convert.py +11 -12
- vdata-0.3.2/vdata/data/name.py +1 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/vdata.py +61 -31
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/view.py +20 -8
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/write.py +25 -20
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/index.py +2 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/view.py +1 -1
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/_functions.py +0 -18
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/array.py +17 -1
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/timepoint.py +6 -4
- vdata-0.3.2/vdata/update/__init__.py +14 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/update/array.py +15 -6
- {vdata-0.3.1 → vdata-0.3.2}/vdata/update/dict.py +15 -7
- {vdata-0.3.1 → vdata-0.3.2}/vdata/update/tdf.py +42 -36
- {vdata-0.3.1 → vdata-0.3.2}/vdata/update/update.py +35 -23
- {vdata-0.3.1 → vdata-0.3.2}/vdata/update/vdf.py +24 -14
- vdata-0.3.1/vdata/IO/logger.conf +0 -27
- vdata-0.3.1/vdata/update/__init__.py +0 -6
- {vdata-0.3.1 → vdata-0.3.2}/LICENSE +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/README.md +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/IO/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/IO/errors.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/IO/logger.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/_meta.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/anndata_proxy/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/anndata_proxy/dataframe.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/cli.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/anndata.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/data.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/objects/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/objects/layers.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/objects/objects.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/objects/obs.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/objects/uns.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/objects/var.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/_parse/utils.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/arrays/lazy.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/hash.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/data/read.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/names.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/py.typed +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/_parse.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/base.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/dataframe.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/indexers.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/tdf/indexing.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/__init__.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/_typing.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/index.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/timepoint/range.py +0 -0
- {vdata-0.3.1 → vdata-0.3.2}/vdata/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: vdata
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Annotated multivariate observation of timestamped data
|
|
5
5
|
Author: Matteo Bouvier
|
|
6
6
|
Author-email: Matteo Bouvier <matteo.bouvier@hotmail.fr>
|
|
@@ -11,7 +11,7 @@ Requires-Dist: anndata>=0.10.4
|
|
|
11
11
|
Requires-Dist: scipy>=1.12.0
|
|
12
12
|
Requires-Dist: numpy-indexed>=0.3.7
|
|
13
13
|
Requires-Dist: ch5mpy>=0.5.1
|
|
14
|
-
Requires-Dist: ezarr>=1.1.
|
|
14
|
+
Requires-Dist: ezarr>=1.1.1
|
|
15
15
|
Requires-Dist: h5dataframe>=0.2.3 ; extra == 'update'
|
|
16
16
|
Requires-Python: >=3.12
|
|
17
17
|
Provides-Extra: update
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "vdata"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.2"
|
|
4
4
|
description = "Annotated multivariate observation of timestamped data"
|
|
5
5
|
authors = [{ name = "Matteo Bouvier", email="matteo.bouvier@hotmail.fr"}]
|
|
6
6
|
license = "CECILL-B"
|
|
@@ -14,7 +14,7 @@ dependencies = [
|
|
|
14
14
|
"scipy>=1.12.0",
|
|
15
15
|
"numpy-indexed>=0.3.7",
|
|
16
16
|
"ch5mpy>=0.5.1",
|
|
17
|
-
"ezarr>=1.1.
|
|
17
|
+
"ezarr>=1.1.1",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
[dependency-groups]
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Annotated, temporal and multivariate observation data."""
|
|
2
2
|
|
|
3
|
+
from importlib.metadata import metadata
|
|
4
|
+
|
|
3
5
|
from vdata.data import VData, VDataView, concatenate, convert_anndata_to_vdata
|
|
4
6
|
from vdata.IO import (
|
|
5
7
|
IncoherenceError,
|
|
@@ -9,13 +11,15 @@ from vdata.IO import (
|
|
|
9
11
|
)
|
|
10
12
|
from vdata.tdf import RepeatingIndex, TemporalDataFrame, TemporalDataFrameView
|
|
11
13
|
from vdata.timepoint import TimePoint
|
|
12
|
-
from vdata.update import CURRENT_VERSION, update_vdata
|
|
13
14
|
|
|
14
15
|
read = VData.read
|
|
15
16
|
read_from_csv = VData.read_from_csv
|
|
16
17
|
read_from_anndata = VData.read_from_anndata
|
|
17
18
|
read_from_pickle = VData.read_from_pickle
|
|
18
19
|
|
|
20
|
+
__version__ = metadata("vdata").get("version")
|
|
21
|
+
|
|
22
|
+
|
|
19
23
|
__all__ = [
|
|
20
24
|
"VData",
|
|
21
25
|
"TemporalDataFrame",
|
|
@@ -29,6 +33,4 @@ __all__ = [
|
|
|
29
33
|
"VLockError",
|
|
30
34
|
"TimePoint",
|
|
31
35
|
"RepeatingIndex",
|
|
32
|
-
"CURRENT_VERSION",
|
|
33
|
-
"update_vdata",
|
|
34
36
|
]
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
from collections.abc import Collection
|
|
1
|
+
from collections.abc import Collection
|
|
2
2
|
from types import EllipsisType
|
|
3
3
|
from typing import SupportsIndex, TypedDict
|
|
4
4
|
|
|
5
|
-
import ezarr as ez
|
|
6
5
|
import numpy as np
|
|
7
6
|
import numpy.typing as npt
|
|
8
7
|
import zarr
|
|
@@ -23,7 +22,6 @@ type NDArrayLike_IFS = npt.NDArray[np_IFS] | zarr.Array
|
|
|
23
22
|
type AnyNDArrayLike_IFS = npt.NDArray[np_IFS] | NDArrayView[np_IFS] | zarr.Array
|
|
24
23
|
|
|
25
24
|
type Collection_IFS = Collection[IFS]
|
|
26
|
-
type DictLike[T: ez.SupportsEZReadWrite] = MutableMapping[str, T] | ez.EZDict[T]
|
|
27
25
|
|
|
28
26
|
type Slicer = IFS | tp.TimePoint | Collection[IFS | tp.TimePoint] | range | slice | EllipsisType
|
|
29
27
|
type MultiSlicer = Collection[IFS | tp.TimePoint] | range | slice | EllipsisType
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from collections.abc import Sequence
|
|
4
|
-
from
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Literal, override
|
|
3
|
+
from collections.abc import MutableMapping, Sequence
|
|
4
|
+
from os import PathLike
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal, final, override
|
|
6
6
|
|
|
7
7
|
import numpy.typing as npt
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from anndata import AnnData
|
|
10
|
+
from ezarr.dataframe import EZDataFrame
|
|
10
11
|
from scipy import sparse
|
|
11
12
|
|
|
12
|
-
from vdata._typing import AnyNDArrayLike
|
|
13
|
+
from vdata._typing import AnyNDArrayLike
|
|
13
14
|
from vdata.anndata_proxy.containers import ArrayStack2DProxy, EZDataFrameContainerProxy, TemporalDataFrameContainerProxy
|
|
14
15
|
from vdata.anndata_proxy.dataframe import DataFrameProxy_TDF
|
|
15
16
|
|
|
@@ -19,25 +20,26 @@ if TYPE_CHECKING:
|
|
|
19
20
|
|
|
20
21
|
def skip_time_axis(slicer: Any) -> tuple[Any, ...]:
|
|
21
22
|
if isinstance(slicer, tuple):
|
|
22
|
-
return (slice(None),) + slicer
|
|
23
|
+
return (slice(None),) + slicer # pyright: ignore[reportUnknownVariableType]
|
|
23
24
|
|
|
24
25
|
return (slice(None), slicer)
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
@final
|
|
29
|
+
class AnnDataProxy(AnnData):
|
|
28
30
|
"""
|
|
29
31
|
Class faking to be an anndata.AnnData object but actually wrapping a VData.
|
|
30
32
|
"""
|
|
31
33
|
|
|
32
34
|
__slots__: tuple[str, ...] = "_vdata", "_X", "_layers", "_obs", "_obsm", "_obsp", "_var", "_varm", "_varp", "_uns"
|
|
33
35
|
|
|
34
|
-
def __init__(self, vdata: VData | VDataView, X: str | None = None) -> None:
|
|
36
|
+
def __init__(self, vdata: VData | VDataView, X: str | None = None) -> None: # pyright: ignore[reportMissingSuperCall]
|
|
35
37
|
"""
|
|
36
38
|
Args:
|
|
37
39
|
vdata: a VData object to wrap.
|
|
38
40
|
X: an optional layer name to use as X.
|
|
39
41
|
"""
|
|
40
|
-
self._X = None if X is None else str(X)
|
|
42
|
+
self._X: str | None = None if X is None else str(X) # pyright: ignore[reportConstantRedefinition]
|
|
41
43
|
|
|
42
44
|
if self._X is not None and self._X not in vdata.layers:
|
|
43
45
|
raise ValueError(f"Could not find layer '{self._X}' in the given VData.")
|
|
@@ -55,32 +57,40 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
55
57
|
self._varp = EZDataFrameContainerProxy(vdata.varp, name="Varp", index=vdata.var.index, columns=vdata.var.index)
|
|
56
58
|
self._uns = vdata.uns
|
|
57
59
|
|
|
60
|
+
@override
|
|
58
61
|
def __repr__(self) -> str:
|
|
59
62
|
return f"AnnDataProxy from {self._vdata}"
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
@override
|
|
65
|
+
def __sizeof__(self, *, show_stratified: bool | None = None, with_disk: bool = False) -> int:
|
|
62
66
|
del show_stratified, with_disk
|
|
63
67
|
raise NotImplementedError
|
|
64
68
|
|
|
69
|
+
@override
|
|
65
70
|
def __delitem__(self, index: Any) -> None:
|
|
66
71
|
raise NotImplementedError
|
|
67
72
|
|
|
73
|
+
@override
|
|
68
74
|
def __getitem__(self, index: Any) -> AnnDataProxy:
|
|
69
75
|
"""Returns a sliced view of the object."""
|
|
70
76
|
return AnnDataProxy(self._vdata[skip_time_axis(index)], X=self._X)
|
|
71
77
|
|
|
78
|
+
@override
|
|
72
79
|
def __setitem__(self, index: Any, val: int | float | npt.NDArray[Any] | sparse.spmatrix) -> None:
|
|
73
80
|
raise NotImplementedError
|
|
74
81
|
|
|
75
82
|
@property
|
|
76
|
-
|
|
83
|
+
@override
|
|
84
|
+
def n_obs(self) -> int:
|
|
77
85
|
return self._vdata.n_obs_total
|
|
78
86
|
|
|
79
87
|
@property
|
|
80
|
-
|
|
88
|
+
@override
|
|
89
|
+
def n_vars(self) -> int:
|
|
81
90
|
return self._vdata.n_var
|
|
82
91
|
|
|
83
92
|
@property
|
|
93
|
+
@override
|
|
84
94
|
def X(self) -> AnyNDArrayLike[Any] | None:
|
|
85
95
|
if self._X is None:
|
|
86
96
|
return None
|
|
@@ -91,15 +101,16 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
91
101
|
if isinstance(value, ArrayStack2DProxy):
|
|
92
102
|
if value.layer_name is None:
|
|
93
103
|
self._layers["X"] = value.stack()
|
|
94
|
-
self._X = "X"
|
|
104
|
+
self._X = "X" # pyright: ignore[reportConstantRedefinition]
|
|
95
105
|
|
|
96
106
|
raise NotImplementedError
|
|
97
107
|
|
|
98
108
|
@X.deleter
|
|
99
109
|
def X(self) -> None:
|
|
100
|
-
self._X = None
|
|
110
|
+
self._X = None # pyright: ignore[reportConstantRedefinition]
|
|
101
111
|
|
|
102
112
|
@property
|
|
113
|
+
@override
|
|
103
114
|
def layers(self) -> TemporalDataFrameContainerProxy:
|
|
104
115
|
return self._layers
|
|
105
116
|
|
|
@@ -113,11 +124,12 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
113
124
|
raise NotImplementedError
|
|
114
125
|
|
|
115
126
|
@property
|
|
116
|
-
|
|
127
|
+
@override
|
|
128
|
+
def raw(self) -> None: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
117
129
|
raise NotImplementedError
|
|
118
130
|
|
|
119
131
|
@raw.setter
|
|
120
|
-
def raw(self, value: AnnData) -> None:
|
|
132
|
+
def raw(self, value: AnnData) -> None: # pyright: ignore[reportPropertyTypeMismatch]
|
|
121
133
|
raise NotImplementedError
|
|
122
134
|
|
|
123
135
|
@raw.deleter
|
|
@@ -125,11 +137,12 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
125
137
|
raise NotImplementedError
|
|
126
138
|
|
|
127
139
|
@property
|
|
128
|
-
|
|
140
|
+
@override
|
|
141
|
+
def obs(self) -> DataFrameProxy_TDF: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
129
142
|
return self._obs
|
|
130
143
|
|
|
131
144
|
@obs.setter
|
|
132
|
-
def obs(self, value: pd.DataFrame) -> None:
|
|
145
|
+
def obs(self, value: pd.DataFrame) -> None: # pyright: ignore[reportPropertyTypeMismatch]
|
|
133
146
|
raise NotImplementedError
|
|
134
147
|
|
|
135
148
|
@obs.deleter
|
|
@@ -137,21 +150,23 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
137
150
|
raise NotImplementedError
|
|
138
151
|
|
|
139
152
|
@property
|
|
153
|
+
@override
|
|
140
154
|
def obs_names(self) -> pd.Index:
|
|
141
155
|
"""Names of observations (alias for `.obs.index`)."""
|
|
142
156
|
return self.obs.index
|
|
143
157
|
|
|
144
158
|
@obs_names.setter
|
|
145
|
-
def obs_names(self, names: Sequence[str]) -> None:
|
|
159
|
+
def obs_names(self, names: Sequence[str]) -> None: # pyright: ignore[reportPropertyTypeMismatch]
|
|
146
160
|
raise NotImplementedError
|
|
147
161
|
|
|
148
162
|
@property
|
|
163
|
+
@override
|
|
149
164
|
def var(self) -> EZDataFrame:
|
|
150
165
|
"""One-dimensional annotation of variables/ features (`pd.DataFrame`)."""
|
|
151
166
|
return self._var
|
|
152
167
|
|
|
153
168
|
@var.setter
|
|
154
|
-
def var(self, value: pd.DataFrame) -> None:
|
|
169
|
+
def var(self, value: pd.DataFrame) -> None: # pyright: ignore[reportPropertyTypeMismatch]
|
|
155
170
|
raise NotImplementedError
|
|
156
171
|
|
|
157
172
|
@var.deleter
|
|
@@ -159,21 +174,23 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
159
174
|
raise NotImplementedError
|
|
160
175
|
|
|
161
176
|
@property
|
|
177
|
+
@override
|
|
162
178
|
def var_names(self) -> pd.Index:
|
|
163
179
|
"""Names of variables (alias for `.var.index`)."""
|
|
164
180
|
return self.var.index
|
|
165
181
|
|
|
166
182
|
@var_names.setter
|
|
167
|
-
def var_names(self, names: Sequence[str]) -> None:
|
|
183
|
+
def var_names(self, names: Sequence[str]) -> None: # pyright: ignore[reportPropertyTypeMismatch]
|
|
168
184
|
raise NotImplementedError
|
|
169
185
|
|
|
170
186
|
@property
|
|
171
|
-
|
|
187
|
+
@override
|
|
188
|
+
def uns(self) -> MutableMapping[str, Any]:
|
|
172
189
|
"""Unstructured annotation (ordered dictionary)."""
|
|
173
190
|
return self._uns
|
|
174
191
|
|
|
175
192
|
@uns.setter
|
|
176
|
-
def uns(self, value:
|
|
193
|
+
def uns(self, value: MutableMapping[str, Any]) -> None:
|
|
177
194
|
raise NotImplementedError
|
|
178
195
|
|
|
179
196
|
@uns.deleter
|
|
@@ -181,6 +198,7 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
181
198
|
raise NotImplementedError
|
|
182
199
|
|
|
183
200
|
@property
|
|
201
|
+
@override
|
|
184
202
|
def obsm(self) -> TemporalDataFrameContainerProxy:
|
|
185
203
|
return self._obsm
|
|
186
204
|
|
|
@@ -193,6 +211,7 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
193
211
|
raise NotImplementedError
|
|
194
212
|
|
|
195
213
|
@property
|
|
214
|
+
@override
|
|
196
215
|
def varm(self) -> EZDataFrameContainerProxy:
|
|
197
216
|
return self._varm
|
|
198
217
|
|
|
@@ -205,6 +224,7 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
205
224
|
raise NotImplementedError
|
|
206
225
|
|
|
207
226
|
@property
|
|
227
|
+
@override
|
|
208
228
|
def obsp(self) -> EZDataFrameContainerProxy:
|
|
209
229
|
return self._obsp
|
|
210
230
|
|
|
@@ -217,6 +237,7 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
217
237
|
raise NotImplementedError
|
|
218
238
|
|
|
219
239
|
@property
|
|
240
|
+
@override
|
|
220
241
|
def varp(self) -> EZDataFrameContainerProxy:
|
|
221
242
|
return self._varp
|
|
222
243
|
|
|
@@ -265,15 +286,19 @@ class AnnDataProxy(AnnData): # type: ignore[misc]
|
|
|
265
286
|
self._init_from_vdata(self._vdata[skip_time_axis(index)])
|
|
266
287
|
|
|
267
288
|
@override
|
|
268
|
-
def copy(self, filename:
|
|
289
|
+
def copy(self, filename: PathLike[str] | str | None = None) -> AnnData:
|
|
269
290
|
"""Full copy, optionally on disk."""
|
|
291
|
+
AnnData.copy
|
|
270
292
|
raise NotImplementedError
|
|
271
293
|
|
|
294
|
+
@override
|
|
272
295
|
def write_h5ad(
|
|
273
296
|
self,
|
|
274
|
-
filename:
|
|
297
|
+
filename: PathLike[str] | str | None = None,
|
|
298
|
+
*,
|
|
299
|
+
convert_strings_to_categoricals: bool = True,
|
|
275
300
|
compression: Literal["gzip", "lzf"] | None = None,
|
|
276
|
-
compression_opts: Any = None,
|
|
301
|
+
compression_opts: int | Any = None,
|
|
277
302
|
as_dense: Sequence[str] = (),
|
|
278
303
|
) -> None:
|
|
279
304
|
raise NotImplementedError
|
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import operator as op
|
|
4
|
-
from
|
|
5
|
-
from typing import (
|
|
6
|
-
Any,
|
|
7
|
-
Callable,
|
|
8
|
-
ClassVar,
|
|
4
|
+
from collections.abc import (
|
|
9
5
|
Collection,
|
|
10
6
|
ItemsView,
|
|
11
7
|
KeysView,
|
|
12
8
|
MutableMapping,
|
|
13
|
-
Union,
|
|
14
9
|
ValuesView,
|
|
10
|
+
)
|
|
11
|
+
from functools import partialmethod
|
|
12
|
+
from typing import (
|
|
13
|
+
Any,
|
|
14
|
+
Callable,
|
|
15
|
+
ClassVar,
|
|
15
16
|
cast,
|
|
17
|
+
final,
|
|
16
18
|
override,
|
|
17
19
|
)
|
|
18
20
|
|
|
19
21
|
import numpy as np
|
|
20
22
|
import numpy.typing as npt
|
|
23
|
+
import pandas as pd
|
|
21
24
|
import scipy.sparse as ss
|
|
25
|
+
from ezarr.dataframe import EZDataFrame
|
|
22
26
|
|
|
23
|
-
# from h5dataframe import EZDataFrame
|
|
24
27
|
import vdata
|
|
25
|
-
from vdata._typing import IFS, AnyNDArrayLike
|
|
28
|
+
from vdata._typing import IFS, AnyNDArrayLike
|
|
26
29
|
from vdata.tdf import TemporalDataFrame, TemporalDataFrameBase
|
|
30
|
+
from vdata.tdf.index import RepeatingIndex
|
|
27
31
|
|
|
28
32
|
type _NP_IF = np.integer | np.floating
|
|
29
33
|
|
|
@@ -77,7 +81,7 @@ class ArrayStack2DProxy:
|
|
|
77
81
|
) -> None:
|
|
78
82
|
self._array_numeric: AnyNDArrayLike[_NP_IF] | None = array_numeric if array_numeric.size else None
|
|
79
83
|
self._array_string: AnyNDArrayLike[_NP_IF] | None = array_string if array_string.size else None
|
|
80
|
-
self.layer_name: str = layer_name
|
|
84
|
+
self.layer_name: str | None = layer_name
|
|
81
85
|
|
|
82
86
|
@override
|
|
83
87
|
def __repr__(self) -> str:
|
|
@@ -176,6 +180,7 @@ class ArrayStack2DProxy:
|
|
|
176
180
|
)
|
|
177
181
|
|
|
178
182
|
|
|
183
|
+
@final
|
|
179
184
|
class EZDataFrameContainerProxy:
|
|
180
185
|
__slots__: tuple[str, ...] = "_h5dfs", "_index", "_columns", "_name", "_sparse_matrices"
|
|
181
186
|
|
|
@@ -183,8 +188,8 @@ class EZDataFrameContainerProxy:
|
|
|
183
188
|
self,
|
|
184
189
|
h5dfs: MutableMapping[str, EZDataFrame],
|
|
185
190
|
name: str,
|
|
186
|
-
index:
|
|
187
|
-
columns:
|
|
191
|
+
index: RepeatingIndex | pd.Index,
|
|
192
|
+
columns: RepeatingIndex | pd.Index | None = None,
|
|
188
193
|
) -> None:
|
|
189
194
|
self._h5dfs = h5dfs
|
|
190
195
|
self._index = index
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from collections.abc import Iterable, Iterator
|
|
3
|
+
from collections.abc import Collection, Iterable, Iterator
|
|
4
4
|
from typing import TYPE_CHECKING, Any, SupportsIndex, cast, overload, override
|
|
5
5
|
|
|
6
6
|
import ch5mpy.indexing as ci
|
|
@@ -25,7 +25,7 @@ _RESERVED_ATTRIBUTES = frozenset(
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
class NDArrayView[T: np.generic | TimePoint](
|
|
28
|
+
class NDArrayView[T: np.generic | TimePoint](Collection[T]):
|
|
29
29
|
"""View on a numpy ndarray that can be subsetted infinitely without copying."""
|
|
30
30
|
|
|
31
31
|
__slots__: tuple[str, ...] = "_array", "_index", "_exposed_attr"
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from vdata.data.concatenate import concatenate
|
|
2
2
|
from vdata.data.convert import convert_anndata_to_vdata
|
|
3
|
+
from vdata.data.name import WRITE_PROTOCOL_VERSION
|
|
3
4
|
from vdata.data.vdata import VData
|
|
4
5
|
from vdata.data.view import VDataView
|
|
5
6
|
|
|
6
7
|
__all__ = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
"VData",
|
|
9
|
+
"VDataView",
|
|
10
|
+
"concatenate",
|
|
11
|
+
"convert_anndata_to_vdata",
|
|
12
|
+
"WRITE_PROTOCOL_VERSION",
|
|
11
13
|
]
|
|
@@ -53,7 +53,7 @@ def slicer_to_array(
|
|
|
53
53
|
return np.array(reference_index)[np.where(slicer.flatten())]
|
|
54
54
|
|
|
55
55
|
if isinstance(slicer, tp.TimePointNArray):
|
|
56
|
-
return slicer[np.where(np.
|
|
56
|
+
return slicer[np.where(np.isin(slicer, reference_index))]
|
|
57
57
|
|
|
58
58
|
if not isCollection(slicer):
|
|
59
59
|
return np.array([slicer]) if slicer in reference_index else np.array([])
|
|
@@ -63,7 +63,7 @@ def slicer_to_array(
|
|
|
63
63
|
if slicer.dtype == bool:
|
|
64
64
|
return reference_index[slicer]
|
|
65
65
|
|
|
66
|
-
return slicer[np.where(np.
|
|
66
|
+
return slicer[np.where(np.isin(slicer, reference_index))]
|
|
67
67
|
|
|
68
68
|
|
|
69
69
|
def _gets_whole_axis(slicer: PreSlicer) -> bool:
|
|
@@ -44,7 +44,7 @@ def parse_timepoints_list(
|
|
|
44
44
|
def parse_timepoints(timepoints: pd.DataFrame | EZDataFrame | None) -> EZDataFrame:
|
|
45
45
|
if timepoints is None:
|
|
46
46
|
generalLogger.debug(" 'time points' DataFrame was not given.")
|
|
47
|
-
return EZDataFrame(pd.DataFrame(columns=np.array(["value"])))
|
|
47
|
+
return EZDataFrame(pd.DataFrame(columns=np.array(["value"]), dtype=float))
|
|
48
48
|
|
|
49
49
|
if not isinstance(timepoints, (pd.DataFrame, EZDataFrame)): # pyright: ignore[reportUnnecessaryIsInstance]
|
|
50
50
|
raise TypeError(f"'time points' must be a DataFrame, got '{type(timepoints).__name__}'.") # pyright: ignore[reportUnreachable]
|
|
@@ -55,7 +55,7 @@ def parse_timepoints(timepoints: pd.DataFrame | EZDataFrame | None) -> EZDataFra
|
|
|
55
55
|
timepoints_col = tp.as_timepointarray(timepoints["value"])
|
|
56
56
|
timepoints_col.sort()
|
|
57
57
|
timepoints = EZDataFrame(timepoints.drop("value", axis=1))
|
|
58
|
-
timepoints.insert(0, "value", timepoints_col)
|
|
58
|
+
timepoints.insert(0, "value", timepoints_col) # pyright: ignore[reportArgumentType]
|
|
59
59
|
log_timepoints(timepoints)
|
|
60
60
|
|
|
61
61
|
return timepoints
|
|
@@ -81,11 +81,11 @@ def check_time_match(data: ParsingDataIn) -> None:
|
|
|
81
81
|
|
|
82
82
|
# check that timepoints and _time_list and _time_col_name match
|
|
83
83
|
if data.timepoints_list is not None and not np.all(
|
|
84
|
-
np.
|
|
84
|
+
np.isin(data.timepoints_list, tp.as_timepointarray(data.timepoints.value))
|
|
85
85
|
):
|
|
86
86
|
raise ValueError("There are values in 'timepoints_list' unknown in 'timepoints'.")
|
|
87
87
|
|
|
88
88
|
elif data.time_col_name is not None and not np.all(
|
|
89
|
-
np.
|
|
89
|
+
np.isin(tp.as_timepointarray(data.obs.timepoints), tp.as_timepointarray(data.timepoints.value))
|
|
90
90
|
):
|
|
91
91
|
raise ValueError(f"There are values in obs['{data.time_col_name}'] unknown in 'timepoints'.")
|
|
@@ -10,21 +10,17 @@ import pandas as pd
|
|
|
10
10
|
from ezarr.dataframe import EZDataFrame
|
|
11
11
|
|
|
12
12
|
import vdata
|
|
13
|
-
from vdata._typing import IFS
|
|
14
|
-
|
|
15
|
-
# from vdata.data.arrays.lazy import LazyLoc
|
|
13
|
+
from vdata._typing import IFS
|
|
14
|
+
from vdata.data.arrays.lazy import LazyLoc
|
|
16
15
|
from vdata.IO import generalLogger
|
|
17
16
|
from vdata.tdf import RepeatingIndex, TemporalDataFrame, TemporalDataFrameView
|
|
18
17
|
from vdata.tdf.base import TemporalDataFrameBase
|
|
19
18
|
from vdata.utils import first_in
|
|
20
19
|
|
|
21
|
-
# D = TypeVar("D", Union[TemporalDataFrame, TemporalDataFrameView], TemporalDataFrameView, EZDataFrame, LazyLoc)
|
|
22
|
-
# D_copy = TypeVar("D_copy", TemporalDataFrame, pd.DataFrame)
|
|
23
|
-
|
|
24
20
|
|
|
25
21
|
# Base Containers -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
|
26
22
|
class ArrayContainerMixin[
|
|
27
|
-
D: TemporalDataFrameBase | EZDataFrame,
|
|
23
|
+
D: TemporalDataFrameBase | EZDataFrame | LazyLoc,
|
|
28
24
|
D_copy: TemporalDataFrame | pd.DataFrame,
|
|
29
25
|
](MutableMapping[str, D], ABC):
|
|
30
26
|
@property
|
|
@@ -119,7 +115,7 @@ class VBaseArrayContainer[
|
|
|
119
115
|
|
|
120
116
|
__slots__: tuple[str, ...] = "_vdata", "_data"
|
|
121
117
|
|
|
122
|
-
def __init__(self, *, data:
|
|
118
|
+
def __init__(self, *, data: MutableMapping[str, D], vdata: vdata.VData):
|
|
123
119
|
"""
|
|
124
120
|
Args:
|
|
125
121
|
vdata: the parent VData object this ArrayContainer is linked to.
|
|
@@ -129,10 +125,10 @@ class VBaseArrayContainer[
|
|
|
129
125
|
generalLogger.debug(f"== Creating {type(self).__name__}. ==========================")
|
|
130
126
|
|
|
131
127
|
self._vdata: vdata.VData = vdata
|
|
132
|
-
self._data:
|
|
128
|
+
self._data: MutableMapping[str, D] = self._check_init_data(data)
|
|
133
129
|
|
|
134
130
|
@abstractmethod
|
|
135
|
-
def _check_init_data(self, data:
|
|
131
|
+
def _check_init_data(self, data: MutableMapping[str, D]) -> MutableMapping[str, D]:
|
|
136
132
|
"""
|
|
137
133
|
Function for checking, at ArrayContainer creation, that the supplied data has the correct format.
|
|
138
134
|
|
|
@@ -230,7 +226,7 @@ class VBaseArrayContainer[
|
|
|
230
226
|
pass
|
|
231
227
|
|
|
232
228
|
@property
|
|
233
|
-
def data(self) ->
|
|
229
|
+
def data(self) -> MutableMapping[str, D]:
|
|
234
230
|
"""
|
|
235
231
|
Data of this ArrayContainer.
|
|
236
232
|
|
|
@@ -277,7 +273,7 @@ class VTDFArrayContainer(VBaseArrayContainer[TemporalDataFrame | TemporalDataFra
|
|
|
277
273
|
It is based on VBaseArrayContainer and defines some functions shared by obsm and layers.
|
|
278
274
|
"""
|
|
279
275
|
|
|
280
|
-
def __init__(self, *, data:
|
|
276
|
+
def __init__(self, *, data: MutableMapping[str, TemporalDataFrame | TemporalDataFrameView], vdata: vdata.VData):
|
|
281
277
|
"""
|
|
282
278
|
Args:
|
|
283
279
|
parent: the parent VData object this ArrayContainer is linked to.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import MutableMapping
|
|
3
4
|
from typing import override
|
|
4
5
|
|
|
5
6
|
import ezarr as ez
|
|
@@ -21,8 +22,8 @@ class VLayersArrayContainer(VTDFArrayContainer):
|
|
|
21
22
|
|
|
22
23
|
@override
|
|
23
24
|
def _check_init_data(
|
|
24
|
-
self, data:
|
|
25
|
-
) ->
|
|
25
|
+
self, data: MutableMapping[str, TemporalDataFrame | TemporalDataFrameView]
|
|
26
|
+
) -> MutableMapping[str, TemporalDataFrame | TemporalDataFrameView]:
|
|
26
27
|
"""
|
|
27
28
|
Function for checking, at VLayerArrayContainer creation, that the supplied data has the correct format :
|
|
28
29
|
- the shape of the TemporalDataFrames in 'data' match the parent VData object's shape.
|
|
@@ -44,7 +45,9 @@ class VLayersArrayContainer(VTDFArrayContainer):
|
|
|
44
45
|
generalLogger.debug(" Data was found.")
|
|
45
46
|
|
|
46
47
|
_shape = (self._vdata.timepoints.shape[0], self._vdata.obs.shape[1], self._vdata.var.shape[0])
|
|
47
|
-
_data:
|
|
48
|
+
_data: MutableMapping[str, TemporalDataFrame | TemporalDataFrameView] = (
|
|
49
|
+
{} if not isinstance(data, ez.EZDict) else data
|
|
50
|
+
)
|
|
48
51
|
|
|
49
52
|
generalLogger.debug(f" Reference shape is {_shape}.")
|
|
50
53
|
|
|
@@ -83,8 +83,7 @@ class VObsmArrayContainer(VTDFArrayContainer):
|
|
|
83
83
|
f"Time points of TemporalDataFrame '{TDF_index}' ({tdf.timepoints}) do not match time_point's index. ({self._vdata.timepoints.value.values})"
|
|
84
84
|
)
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
tdf.lock_indices()
|
|
86
|
+
tdf.lock_indices()
|
|
88
87
|
|
|
89
88
|
if isinstance(data, dict):
|
|
90
89
|
_data[str(TDF_index)] = tdf
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from collections.abc import Collection
|
|
3
|
+
from collections.abc import Collection, MutableMapping
|
|
4
4
|
from typing import cast, override
|
|
5
5
|
|
|
6
6
|
import ezarr as ez
|
|
@@ -8,7 +8,7 @@ import numpy.typing as npt
|
|
|
8
8
|
import pandas as pd
|
|
9
9
|
from ezarr.dataframe import EZDataFrame
|
|
10
10
|
|
|
11
|
-
from vdata._typing import IFS,
|
|
11
|
+
from vdata._typing import IFS, np_IFS
|
|
12
12
|
from vdata.data.arrays.base import VBaseArrayContainer
|
|
13
13
|
from vdata.data.arrays.lazy import LazyLoc
|
|
14
14
|
from vdata.data.arrays.view import VBaseArrayContainerView
|
|
@@ -21,7 +21,7 @@ from vdata.IO import (
|
|
|
21
21
|
from vdata.utils import first_in
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
class VVarmArrayContainer(VBaseArrayContainer[pd.DataFrame
|
|
24
|
+
class VVarmArrayContainer(VBaseArrayContainer[EZDataFrame, pd.DataFrame]):
|
|
25
25
|
"""
|
|
26
26
|
Class for varm.
|
|
27
27
|
This object contains any number of DataFrames, with shape (n_var, any).
|
|
@@ -30,7 +30,7 @@ class VVarmArrayContainer(VBaseArrayContainer[pd.DataFrame | EZDataFrame]):
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
@override
|
|
33
|
-
def _check_init_data(self, data:
|
|
33
|
+
def _check_init_data(self, data: MutableMapping[str, EZDataFrame]) -> MutableMapping[str, EZDataFrame]:
|
|
34
34
|
"""
|
|
35
35
|
Function for checking, at VVarmArrayContainer creation, that the supplied data has the correct format :
|
|
36
36
|
- the index of the DataFrames in 'data' match the index of the parent VData's var DataFrame.
|
|
@@ -42,7 +42,7 @@ class VVarmArrayContainer(VBaseArrayContainer[pd.DataFrame | EZDataFrame]):
|
|
|
42
42
|
generalLogger.debug(" Data was found.")
|
|
43
43
|
|
|
44
44
|
_index = self._vdata.var.index
|
|
45
|
-
_data:
|
|
45
|
+
_data: MutableMapping[str, EZDataFrame] = {} if not isinstance(data, ez.EZDict) else data
|
|
46
46
|
|
|
47
47
|
for DF_index, DF in data.items():
|
|
48
48
|
if not _index.equals(DF.index):
|
|
@@ -97,7 +97,7 @@ class VVarmArrayContainer(VBaseArrayContainer[pd.DataFrame | EZDataFrame]):
|
|
|
97
97
|
arr.index = pd.Index(values)
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
class VVarmArrayContainerView(VBaseArrayContainerView[LazyLoc, pd.DataFrame
|
|
100
|
+
class VVarmArrayContainerView(VBaseArrayContainerView[LazyLoc | EZDataFrame, pd.DataFrame]):
|
|
101
101
|
# region magic methods
|
|
102
102
|
def __init__(self, array_container: VVarmArrayContainer, var_slicer: npt.NDArray[np_IFS]):
|
|
103
103
|
super().__init__(
|
|
@@ -164,7 +164,7 @@ class VVarmArrayContainerView(VBaseArrayContainerView[LazyLoc, pd.DataFrame | EZ
|
|
|
164
164
|
arr.index = pd.Index(values)
|
|
165
165
|
|
|
166
166
|
|
|
167
|
-
class VVarpArrayContainer(VBaseArrayContainer[pd.DataFrame]):
|
|
167
|
+
class VVarpArrayContainer(VBaseArrayContainer[EZDataFrame, pd.DataFrame]):
|
|
168
168
|
"""
|
|
169
169
|
Class for varp.
|
|
170
170
|
This object contains any number of DataFrames, with shape (n_var, n_var).
|
|
@@ -173,7 +173,7 @@ class VVarpArrayContainer(VBaseArrayContainer[pd.DataFrame]): # EZDataFrame,
|
|
|
173
173
|
"""
|
|
174
174
|
|
|
175
175
|
@override
|
|
176
|
-
def _check_init_data(self, data:
|
|
176
|
+
def _check_init_data(self, data: MutableMapping[str, EZDataFrame]) -> MutableMapping[str, EZDataFrame]:
|
|
177
177
|
"""
|
|
178
178
|
Function for checking, at ArrayContainer creation, that the supplied data has the correct format :
|
|
179
179
|
- the index and column names of the DataFrames in 'data' match the index of the parent VData's var
|
|
@@ -186,7 +186,7 @@ class VVarpArrayContainer(VBaseArrayContainer[pd.DataFrame]): # EZDataFrame,
|
|
|
186
186
|
generalLogger.debug(" Data was found.")
|
|
187
187
|
|
|
188
188
|
_index = self._vdata.var.index
|
|
189
|
-
_data:
|
|
189
|
+
_data: MutableMapping[str, EZDataFrame] = {} if not isinstance(data, ez.EZDict) else data
|
|
190
190
|
|
|
191
191
|
for DF_index, DF in data.items():
|
|
192
192
|
if not _index.equals(DF.index):
|