transformnd 0.9.2__tar.gz → 0.10.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {transformnd-0.9.2 → transformnd-0.10.1}/PKG-INFO +3 -2
- {transformnd-0.9.2 → transformnd-0.10.1}/pyproject.toml +9 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/pyproject.toml.orig +14 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/__init__.py +10 -10
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/adapters/base.py +4 -7
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/adapters/bounding_box.py +4 -2
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/adapters/polars.py +1 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/adapters/shapely.py +2 -2
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/base.py +4 -6
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/extents/bounding_box.py +5 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/graph.py +10 -9
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/spaced.py +3 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/affine.py +11 -10
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/bijection.py +1 -1
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/by_dimension.py +27 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/grid.py +3 -1
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/map_axis.py +4 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/moving_least_squares.py +3 -2
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/project_axis.py +3 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/vector_field.py +2 -2
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/types.py +4 -3
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/util.py +5 -5
- {transformnd-0.9.2 → transformnd-0.10.1}/README.md +0 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/adapters/__init__.py +4 -4
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/adapters/pandas.py +0 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/extents/__init__.py +0 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/extents/base.py +0 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/py.typed +0 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/__init__.py +13 -13
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/reflection.py +0 -0
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/simple.py +4 -4
- {transformnd-0.9.2 → transformnd-0.10.1}/src/transformnd/transforms/thinplate.py +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: transformnd
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
4
4
|
Summary: ND coordinate transformations
|
|
5
5
|
Author: Chris Barnes
|
|
6
6
|
Author-email: Chris Barnes <chris.barnes@gerbi-gmb.de>
|
|
@@ -16,6 +16,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.13
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
19
20
|
Requires-Dist: numpy>=2
|
|
20
21
|
Requires-Dist: networkx>=3
|
|
21
22
|
Requires-Dist: array-api-compat>=1.14
|
|
@@ -28,7 +29,7 @@ Requires-Dist: transformnd[adapters] ; extra == 'all'
|
|
|
28
29
|
Requires-Dist: molesq>=0.4.0 ; extra == 'movingleastsquares'
|
|
29
30
|
Requires-Dist: pandas>=3.0.2 ; extra == 'pandas'
|
|
30
31
|
Requires-Dist: polars>=1.40.1 ; extra == 'polars'
|
|
31
|
-
Requires-Dist: shapely>=2.
|
|
32
|
+
Requires-Dist: shapely>=2.2 ; extra == 'shapely'
|
|
32
33
|
Requires-Dist: morphops>=0.1.13 ; extra == 'thinplatesplines'
|
|
33
34
|
Requires-Dist: transformnd[thinplatesplines] ; extra == 'transforms'
|
|
34
35
|
Requires-Dist: transformnd[movingleastsquares] ; extra == 'transforms'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "transformnd"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.1"
|
|
4
4
|
description = "ND coordinate transformations"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12, <4.0"
|
|
@@ -23,6 +23,7 @@ classifiers = [
|
|
|
23
23
|
"Programming Language :: Python :: 3.12",
|
|
24
24
|
"Programming Language :: Python :: 3.13",
|
|
25
25
|
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Programming Language :: Python :: 3.15",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
[[project.authors]]
|
|
@@ -38,7 +39,7 @@ issues = "https://github.com/clbarnes/transformnd/issues"
|
|
|
38
39
|
thinplatesplines = ["morphops>=0.1.13"]
|
|
39
40
|
movingleastsquares = ["molesq>=0.4.0"]
|
|
40
41
|
pandas = ["pandas>=3.0.2"]
|
|
41
|
-
shapely = ["shapely>=2.
|
|
42
|
+
shapely = ["shapely>=2.2"]
|
|
42
43
|
polars = ["polars>=1.40.1"]
|
|
43
44
|
vectorfield = ["scipy>=1.17.1"]
|
|
44
45
|
vectorfield-dask = [
|
|
@@ -73,7 +74,7 @@ dev = [
|
|
|
73
74
|
]
|
|
74
75
|
test = [
|
|
75
76
|
"pytest",
|
|
76
|
-
"jax",
|
|
77
|
+
"jax>=0.12",
|
|
77
78
|
"dask>=2026.3.0",
|
|
78
79
|
]
|
|
79
80
|
lint = [
|
|
@@ -90,6 +91,7 @@ examples = [
|
|
|
90
91
|
"scikit-image>=0.26.0",
|
|
91
92
|
"jupytext>=1.19.6",
|
|
92
93
|
"ipykernel>=7.4.0",
|
|
94
|
+
"scipy",
|
|
93
95
|
]
|
|
94
96
|
doc = [
|
|
95
97
|
"pdoc>=16.0.0",
|
|
@@ -122,6 +124,10 @@ external = [
|
|
|
122
124
|
"DOC",
|
|
123
125
|
"D",
|
|
124
126
|
]
|
|
127
|
+
ignore = [
|
|
128
|
+
"C408",
|
|
129
|
+
"UP046",
|
|
130
|
+
]
|
|
125
131
|
|
|
126
132
|
[tool.ruff.lint.extend-per-file-ignores]
|
|
127
133
|
"examples/*.py" = ["E402"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "transformnd"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.1"
|
|
4
4
|
description = "ND coordinate transformations"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Chris Barnes", email = "chris.barnes@gerbi-gmb.de" }]
|
|
@@ -24,6 +24,7 @@ classifiers = [
|
|
|
24
24
|
"Programming Language :: Python :: 3.12",
|
|
25
25
|
"Programming Language :: Python :: 3.13",
|
|
26
26
|
"Programming Language :: Python :: 3.14",
|
|
27
|
+
"Programming Language :: Python :: 3.15",
|
|
27
28
|
]
|
|
28
29
|
|
|
29
30
|
[project.urls]
|
|
@@ -37,7 +38,7 @@ thinplatesplines = [
|
|
|
37
38
|
]
|
|
38
39
|
movingleastsquares = ["molesq>=0.4.0"]
|
|
39
40
|
pandas = ["pandas>=3.0.2"]
|
|
40
|
-
shapely = ["shapely>=2.
|
|
41
|
+
shapely = ["shapely>=2.2"]
|
|
41
42
|
polars = [
|
|
42
43
|
"polars>=1.40.1",
|
|
43
44
|
]
|
|
@@ -69,7 +70,7 @@ dev = [
|
|
|
69
70
|
]
|
|
70
71
|
test = [
|
|
71
72
|
"pytest",
|
|
72
|
-
"jax",
|
|
73
|
+
"jax>=0.12",
|
|
73
74
|
"dask>=2026.3.0",
|
|
74
75
|
]
|
|
75
76
|
lint = [
|
|
@@ -86,6 +87,7 @@ examples = [
|
|
|
86
87
|
"scikit-image>=0.26.0",
|
|
87
88
|
"jupytext>=1.19.6",
|
|
88
89
|
"ipykernel>=7.4.0",
|
|
90
|
+
"scipy",
|
|
89
91
|
]
|
|
90
92
|
doc = [
|
|
91
93
|
"pdoc>=16.0.0",
|
|
@@ -117,6 +119,15 @@ external = [
|
|
|
117
119
|
"DOC", # pydoclint
|
|
118
120
|
"D", # pydocstyle
|
|
119
121
|
]
|
|
122
|
+
ignore = [
|
|
123
|
+
# Would ban dict() in favour of {};
|
|
124
|
+
# I prefer dict() to distinguish from set literals.
|
|
125
|
+
"C408",
|
|
126
|
+
# Prefers type parameters instead of inheriting from Generic[typevar].
|
|
127
|
+
# Currently, we need to use typevars because we python 3.12 doesn't support default type parameters.
|
|
128
|
+
# Should be revisited when python 3.12 is deprecated.
|
|
129
|
+
"UP046",
|
|
130
|
+
]
|
|
120
131
|
|
|
121
132
|
[tool.ruff.lint.extend-per-file-ignores]
|
|
122
133
|
"examples/*.py" = ["E402"]
|
|
@@ -8,25 +8,25 @@ You can find some examples here:
|
|
|
8
8
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
from .
|
|
12
|
-
|
|
13
|
-
from . import transforms
|
|
14
|
-
from . import
|
|
11
|
+
from importlib.metadata import version as _version
|
|
12
|
+
|
|
13
|
+
from . import adapters, transforms
|
|
14
|
+
from .base import Transform, TransformFnWrapper, TransformSequence
|
|
15
15
|
from .graph import TransformGraph
|
|
16
16
|
from .spaced import Spaced
|
|
17
|
-
from
|
|
17
|
+
from .types import NDims, SpaceRef, TransformSignature
|
|
18
18
|
|
|
19
19
|
__version__ = _version("transformnd")
|
|
20
20
|
|
|
21
21
|
__all__ = [
|
|
22
|
+
"NDims",
|
|
23
|
+
"SpaceRef",
|
|
24
|
+
"Spaced",
|
|
22
25
|
"Transform",
|
|
26
|
+
"TransformFnWrapper",
|
|
23
27
|
"TransformGraph",
|
|
24
28
|
"TransformSequence",
|
|
25
|
-
"TransformFnWrapper",
|
|
26
29
|
"TransformSignature",
|
|
27
|
-
"SpaceRef",
|
|
28
|
-
"transforms",
|
|
29
30
|
"adapters",
|
|
30
|
-
"
|
|
31
|
-
"Spaced",
|
|
31
|
+
"transforms",
|
|
32
32
|
]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""Simple adapter cases."""
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Callable
|
|
4
5
|
from copy import deepcopy
|
|
5
6
|
from functools import partial
|
|
6
|
-
from
|
|
7
|
-
from typing import TypeVar, Any
|
|
7
|
+
from typing import Any, TypeVar
|
|
8
8
|
|
|
9
9
|
from array_api_compat import array_namespace
|
|
10
10
|
|
|
11
|
-
from ..base import
|
|
11
|
+
from ..base import ArrayT, Transform
|
|
12
12
|
|
|
13
13
|
ObjectT = TypeVar("ObjectT")
|
|
14
14
|
|
|
@@ -32,7 +32,6 @@ class BaseAdapter[ObjectT, ArrayT](ABC):
|
|
|
32
32
|
ObjectT
|
|
33
33
|
The transformed object.
|
|
34
34
|
"""
|
|
35
|
-
pass
|
|
36
35
|
|
|
37
36
|
def partial(self, *args: Any, **kwargs: Any) -> Callable[..., ObjectT]:
|
|
38
37
|
"""Create a partial function with frozen arguments.
|
|
@@ -135,7 +134,7 @@ class AttrAdapter(BaseAdapter[ObjectT, ArrayT]):
|
|
|
135
134
|
if "got an unexpected keyword argument 'in_place'" in str(e):
|
|
136
135
|
transformed = v.apply(transform, member)
|
|
137
136
|
else:
|
|
138
|
-
raise
|
|
137
|
+
raise
|
|
139
138
|
setattr(obj, k, transformed)
|
|
140
139
|
|
|
141
140
|
return obj
|
|
@@ -149,12 +148,10 @@ class SimpleAdapter(BaseAdapter[ObjectT, ArrayT], ABC):
|
|
|
149
148
|
@abstractmethod
|
|
150
149
|
def _to_array(self, obj: ObjectT) -> ArrayT:
|
|
151
150
|
"""Convert the object into an array of coordinates."""
|
|
152
|
-
pass
|
|
153
151
|
|
|
154
152
|
@abstractmethod
|
|
155
153
|
def _from_array(self, coords: ArrayT) -> ObjectT:
|
|
156
154
|
"""Convert an array of coordinates into the correct type."""
|
|
157
|
-
pass
|
|
158
155
|
|
|
159
156
|
def apply(self, transform: Transform[ArrayT], obj: ObjectT) -> ObjectT:
|
|
160
157
|
coords: ArrayT = self._to_array(obj)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from array_api_compat import array_namespace
|
|
2
|
+
|
|
2
3
|
from transformnd.base import Transform
|
|
3
|
-
|
|
4
|
-
from ..extents.bounding_box import BoundingBox
|
|
4
|
+
|
|
5
5
|
from ..base import ArrayT
|
|
6
|
+
from ..extents.bounding_box import BoundingBox
|
|
7
|
+
from .base import BaseAdapter
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class BoundingBoxAdapter(BaseAdapter[BoundingBox[ArrayT], ArrayT]):
|
|
@@ -3,12 +3,12 @@ from typing import TYPE_CHECKING
|
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
|
-
from ..base import
|
|
6
|
+
from ..base import ArrayT, Transform
|
|
7
7
|
from .base import BaseAdapter
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
|
-
from shapely.geometry.base import BaseGeometry
|
|
11
10
|
from shapely.coords import CoordinateSequence
|
|
11
|
+
from shapely.geometry.base import BaseGeometry
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
logger = logging.getLogger(__name__)
|
|
@@ -5,18 +5,17 @@ from __future__ import annotations
|
|
|
5
5
|
from abc import ABC, abstractmethod
|
|
6
6
|
from collections.abc import Iterator, Sequence
|
|
7
7
|
from copy import copy
|
|
8
|
-
from
|
|
8
|
+
from itertools import pairwise
|
|
9
9
|
from types import ModuleType
|
|
10
|
+
from typing import TYPE_CHECKING, Self
|
|
10
11
|
|
|
11
12
|
from array_api_compat import array_namespace
|
|
12
13
|
|
|
14
|
+
from .types import NDims, TransformSignature
|
|
13
15
|
from .util import (
|
|
14
16
|
ArrayT,
|
|
15
17
|
join_strs,
|
|
16
18
|
)
|
|
17
|
-
from itertools import pairwise
|
|
18
|
-
|
|
19
|
-
from .types import TransformSignature, NDims
|
|
20
19
|
|
|
21
20
|
if TYPE_CHECKING:
|
|
22
21
|
from .transforms import Affine
|
|
@@ -96,7 +95,6 @@ class Transform[ArrayT](ABC):
|
|
|
96
95
|
ArrayT
|
|
97
96
|
Transformed coordinates in the same shape.
|
|
98
97
|
"""
|
|
99
|
-
pass
|
|
100
98
|
|
|
101
99
|
def invert(self) -> Transform[ArrayT] | None:
|
|
102
100
|
"""Invert the transformation, returning `None` if not possible."""
|
|
@@ -117,7 +115,7 @@ class Transform[ArrayT](ABC):
|
|
|
117
115
|
return NotImplemented
|
|
118
116
|
return t
|
|
119
117
|
|
|
120
|
-
def to_device(self, xp: ModuleType, device: str | None = None) -> Self:
|
|
118
|
+
def to_device(self, xp: ModuleType, device: str | None = None) -> Self:
|
|
121
119
|
"""Return a copy of this transform with array parameters placed on the given device.
|
|
122
120
|
|
|
123
121
|
Useful for pre-allocating parameters on GPU before a tight apply() loop,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
from functools import lru_cache
|
|
2
|
+
|
|
2
3
|
from array_api_compat import array_namespace
|
|
4
|
+
from array_api_compat import device as xp_device
|
|
5
|
+
|
|
3
6
|
from ..util import ArrayT
|
|
4
7
|
from .base import Extents
|
|
5
|
-
from array_api_compat import device as xp_device
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
class BoundingBox(Extents[ArrayT]):
|
|
@@ -15,10 +17,10 @@ class BoundingBox(Extents[ArrayT]):
|
|
|
15
17
|
|
|
16
18
|
self.mins = mins
|
|
17
19
|
self.maxes = maxes
|
|
20
|
+
self.extents_cast = lru_cache()(self._extents_cast)
|
|
18
21
|
super().__init__(xp.shape(mins)[0])
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
def extents_cast(self, namespace, device) -> tuple[ArrayT, ArrayT]:
|
|
23
|
+
def _extents_cast(self, namespace, device) -> tuple[ArrayT, ArrayT]:
|
|
22
24
|
return (
|
|
23
25
|
namespace.asarray(self.mins, device=device),
|
|
24
26
|
namespace.asarray(self.maxes, device=device),
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
"""Bridging transforms between known spaces."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping
|
|
4
7
|
from copy import copy, deepcopy
|
|
5
8
|
from functools import lru_cache
|
|
6
|
-
from collections.abc import Callable, Iterable, Iterator, Mapping
|
|
7
|
-
import logging
|
|
8
9
|
from itertools import pairwise
|
|
9
10
|
from types import ModuleType
|
|
10
|
-
from typing import Any, Generic,
|
|
11
|
-
from typing_extensions import TypeVar
|
|
12
|
-
from .spaced import Spaced
|
|
11
|
+
from typing import Any, Generic, Self
|
|
13
12
|
|
|
14
13
|
import networkx as nx
|
|
14
|
+
from typing_extensions import TypeVar
|
|
15
15
|
|
|
16
16
|
from transformnd.transforms.simple import Identity
|
|
17
17
|
|
|
18
|
-
from .transforms.bijection import Bijection
|
|
19
18
|
from .base import Transform, TransformSequence
|
|
20
|
-
from .
|
|
19
|
+
from .spaced import Spaced
|
|
20
|
+
from .transforms.bijection import Bijection
|
|
21
21
|
from .types import SpaceRef
|
|
22
|
+
from .util import ArrayT
|
|
22
23
|
|
|
23
24
|
logger = logging.getLogger(__name__)
|
|
24
25
|
|
|
@@ -56,6 +57,7 @@ class TransformGraph(Generic[ArrayT, SpaceRef]):
|
|
|
56
57
|
given transforms.
|
|
57
58
|
"""
|
|
58
59
|
self.graph = nx.MultiDiGraph()
|
|
60
|
+
self.get_sequence = lru_cache()(self._get_sequence)
|
|
59
61
|
|
|
60
62
|
def ndim(self, space: SpaceRef) -> int | None:
|
|
61
63
|
"""Get the dimensionality of the given space, or None if missing."""
|
|
@@ -196,8 +198,7 @@ class TransformGraph(Generic[ArrayT, SpaceRef]):
|
|
|
196
198
|
|
|
197
199
|
return out
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
def get_sequence(
|
|
201
|
+
def _get_sequence(
|
|
201
202
|
self,
|
|
202
203
|
source_space: SpaceRef,
|
|
203
204
|
target_space: SpaceRef,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from collections.abc import Iterable, Sequence
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Generic, Self
|
|
3
|
+
|
|
3
4
|
from .base import Transform
|
|
4
|
-
from .types import ArrayT, SrcTgt
|
|
5
|
-
from .types import SpaceRef
|
|
5
|
+
from .types import ArrayT, SpaceRef, SrcTgt
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class Spaced(Generic[ArrayT, SpaceRef]):
|
|
@@ -5,18 +5,19 @@ Rigid transformations implemented as affine multiplications.
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import math
|
|
8
|
-
from
|
|
8
|
+
from collections.abc import Container
|
|
9
|
+
from copy import copy
|
|
9
10
|
from types import ModuleType
|
|
11
|
+
from typing import Self
|
|
10
12
|
|
|
11
13
|
import numpy as np
|
|
14
|
+
from array_api_compat import array_namespace
|
|
15
|
+
from array_api_compat import device as xp_device
|
|
12
16
|
from numpy.typing import ArrayLike
|
|
13
17
|
|
|
14
|
-
from
|
|
15
|
-
|
|
16
|
-
from array_api_compat import array_namespace, device as xp_device
|
|
17
|
-
from ..base import Transform, ArrayT
|
|
18
|
-
from ..util import as_floats, is_square
|
|
18
|
+
from ..base import ArrayT, Transform
|
|
19
19
|
from ..types import NDims
|
|
20
|
+
from ..util import as_floats, is_square
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class Affine(Transform[ArrayT]):
|
|
@@ -148,7 +149,7 @@ class Affine(Transform[ArrayT]):
|
|
|
148
149
|
self.matrix @ rhs.matrix,
|
|
149
150
|
)
|
|
150
151
|
|
|
151
|
-
def to_device(self, xp: ModuleType, device: str | None = None) ->
|
|
152
|
+
def to_device(self, xp: ModuleType, device: str | None = None) -> Affine[ArrayT]:
|
|
152
153
|
"""Return a copy with the matrix placed on the given device/backend.
|
|
153
154
|
|
|
154
155
|
Use this before a tight apply() loop to avoid per-call host-to-device
|
|
@@ -291,7 +292,7 @@ class Affine(Transform[ArrayT]):
|
|
|
291
292
|
@classmethod
|
|
292
293
|
def reflection(
|
|
293
294
|
cls,
|
|
294
|
-
axis:
|
|
295
|
+
axis: int | Container[int],
|
|
295
296
|
ndim: int,
|
|
296
297
|
) -> Affine[ArrayT]:
|
|
297
298
|
"""Create an affine reflection.
|
|
@@ -346,7 +347,7 @@ class Affine(Transform[ArrayT]):
|
|
|
346
347
|
@classmethod
|
|
347
348
|
def rotation3(
|
|
348
349
|
cls,
|
|
349
|
-
rotation:
|
|
350
|
+
rotation: float | tuple[float, float, float],
|
|
350
351
|
degrees: bool = True,
|
|
351
352
|
clockwise: bool = False,
|
|
352
353
|
order: tuple[int, int, int] = (0, 1, 2),
|
|
@@ -402,7 +403,7 @@ class Affine(Transform[ArrayT]):
|
|
|
402
403
|
@classmethod
|
|
403
404
|
def shearing(
|
|
404
405
|
cls,
|
|
405
|
-
factor:
|
|
406
|
+
factor: float | np.ndarray,
|
|
406
407
|
ndim: int | None = None,
|
|
407
408
|
) -> Affine[ArrayT]:
|
|
408
409
|
"""Create an affine shear.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
from collections.abc import Iterable
|
|
2
2
|
from typing import Self
|
|
3
|
-
from array_api_compat import array_namespace
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
import numpy as np
|
|
5
|
+
from array_api_compat import array_namespace
|
|
6
6
|
|
|
7
7
|
from ..base import Transform
|
|
8
|
-
from ..util import ArrayT, join_strs
|
|
9
8
|
from ..types import NDims
|
|
9
|
+
from ..util import ArrayT, join_strs
|
|
10
|
+
from .affine import Affine
|
|
11
|
+
from .simple import Identity
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class SubTransform[ArrayT]:
|
|
@@ -164,6 +166,28 @@ class ByDimension(Transform[ArrayT]):
|
|
|
164
166
|
subtransforms=inverted_transforms,
|
|
165
167
|
)
|
|
166
168
|
|
|
169
|
+
def to_affine(self) -> Affine[ArrayT] | None:
|
|
170
|
+
"""Combine the subtransforms' affines, if all subtransforms can be converted.
|
|
171
|
+
|
|
172
|
+
Each subtransform's linear map and translation are placed in the rows of its output axes,
|
|
173
|
+
and the columns of its input axes.
|
|
174
|
+
|
|
175
|
+
Returns
|
|
176
|
+
-------
|
|
177
|
+
Affine[ArrayT] | None
|
|
178
|
+
The affine transformation, if all subtransforms can be converted to affine.
|
|
179
|
+
None otherwise.
|
|
180
|
+
"""
|
|
181
|
+
m = np.zeros((self.ndims.target + 1, self.ndims.source + 1))
|
|
182
|
+
m[-1, -1] = 1
|
|
183
|
+
for t in self.subtransforms:
|
|
184
|
+
sub_affine = t.transform.to_affine()
|
|
185
|
+
if sub_affine is None:
|
|
186
|
+
return None
|
|
187
|
+
m[np.ix_(t.output_axes, t.input_axes)] = sub_affine.matrix[:-1, :-1]
|
|
188
|
+
m[t.output_axes, -1] = sub_affine.matrix[:-1, -1]
|
|
189
|
+
return Affine(m)
|
|
190
|
+
|
|
167
191
|
def is_identity(self) -> bool:
|
|
168
192
|
for t in self.subtransforms:
|
|
169
193
|
if t.input_axes != t.output_axes or not t.transform.is_identity():
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
from typing import Any,
|
|
1
|
+
from typing import Any, Generic, Protocol
|
|
2
2
|
|
|
3
3
|
from array_api_compat import array_namespace
|
|
4
|
+
|
|
4
5
|
from transformnd.types import NDims
|
|
5
6
|
from transformnd.util import join_strs
|
|
7
|
+
|
|
6
8
|
from ..base import Transform
|
|
7
9
|
from ..types import ArrayT
|
|
8
10
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from typing import Self
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import numpy as np
|
|
4
|
+
from array_api_compat import array_namespace
|
|
4
5
|
|
|
5
6
|
from ..base import Transform
|
|
6
|
-
from ..util import ArrayT, join_strs
|
|
7
|
-
from ..types import NDims
|
|
8
7
|
from ..transforms.affine import Affine
|
|
8
|
+
from ..types import NDims
|
|
9
|
+
from ..util import ArrayT, join_strs
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class MapAxis(Transform[ArrayT]):
|
|
@@ -4,10 +4,11 @@ Implementation of Moving Least Squares transformation.
|
|
|
4
4
|
Requires the `movingleastsquares` extra.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
from array_api_compat import array_namespace
|
|
8
|
-
import numpy as np
|
|
9
7
|
from typing import Self
|
|
10
8
|
|
|
9
|
+
import numpy as np
|
|
10
|
+
from array_api_compat import array_namespace
|
|
11
|
+
|
|
11
12
|
from ..base import Transform
|
|
12
13
|
from ..types import NDims
|
|
13
14
|
from ..util import as_floats
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from typing import Self
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
5
6
|
from array_api_compat import array_namespace
|
|
7
|
+
|
|
6
8
|
from transformnd.transforms import Affine
|
|
7
9
|
from transformnd.types import NDims
|
|
10
|
+
|
|
8
11
|
from ..base import Transform
|
|
9
12
|
from ..types import ArrayT
|
|
10
13
|
|
|
@@ -6,9 +6,9 @@ from typing import Self
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from array_api_compat import array_namespace, is_dask_array
|
|
8
8
|
|
|
9
|
+
from ..base import ArrayT, Transform
|
|
9
10
|
from ..types import NDims
|
|
10
|
-
from ..
|
|
11
|
-
from ..util import join_strs, set_scipy_array_api, as_floats
|
|
11
|
+
from ..util import as_floats, join_strs, set_scipy_array_api
|
|
12
12
|
|
|
13
13
|
__all__ = ["Coordinates", "Displacements"]
|
|
14
14
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
from collections.abc import Sequence
|
|
2
|
-
from typing import
|
|
3
|
-
|
|
1
|
+
from collections.abc import Callable, Hashable, Sequence
|
|
2
|
+
from typing import Generic, NamedTuple, Self
|
|
3
|
+
|
|
4
4
|
import numpy as np
|
|
5
|
+
from typing_extensions import TypeVar
|
|
5
6
|
|
|
6
7
|
ArrayT = TypeVar("ArrayT", default=np.ndarray)
|
|
7
8
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"""Utilities used elsewhere in the package."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import logging
|
|
4
4
|
import os
|
|
5
|
-
from types import ModuleType
|
|
6
5
|
import warnings
|
|
7
|
-
import
|
|
6
|
+
from collections.abc import Iterable
|
|
7
|
+
from types import ModuleType
|
|
8
8
|
|
|
9
|
+
import numpy as np
|
|
9
10
|
from array_api_compat import (
|
|
10
11
|
array_namespace,
|
|
11
12
|
is_dask_namespace,
|
|
12
13
|
is_jax_namespace,
|
|
13
14
|
)
|
|
14
|
-
import numpy as np
|
|
15
15
|
|
|
16
16
|
from .types import ArrayT
|
|
17
17
|
|
|
@@ -69,7 +69,7 @@ def chain_or[T](*args: T | None, default: _NoDefault | T = NO_DEFAULT) -> T:
|
|
|
69
69
|
if arg is not None:
|
|
70
70
|
return arg
|
|
71
71
|
if isinstance(default, _NoDefault):
|
|
72
|
-
raise ValueError("No non-None arguments")
|
|
72
|
+
raise ValueError("No non-None arguments") # noqa: TRY004
|
|
73
73
|
return default
|
|
74
74
|
|
|
75
75
|
|
|
File without changes
|
|
@@ -27,13 +27,13 @@ from .polars import PolarsAdapter
|
|
|
27
27
|
from .shapely import ShapelyAdapter
|
|
28
28
|
|
|
29
29
|
__all__ = [
|
|
30
|
+
"AttrAdapter",
|
|
30
31
|
"BaseAdapter",
|
|
31
|
-
"SimpleAdapter",
|
|
32
|
-
"NullAdapter",
|
|
33
32
|
"FnAdapter",
|
|
34
|
-
"
|
|
35
|
-
"ReshapeAdapter",
|
|
33
|
+
"NullAdapter",
|
|
36
34
|
"PandasAdapter",
|
|
37
35
|
"PolarsAdapter",
|
|
36
|
+
"ReshapeAdapter",
|
|
38
37
|
"ShapelyAdapter",
|
|
38
|
+
"SimpleAdapter",
|
|
39
39
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
"""Implementations of some common transforms."""
|
|
2
2
|
|
|
3
3
|
from .affine import Affine
|
|
4
|
-
from .grid import GridInterpolation
|
|
5
|
-
from .reflection import Reflect
|
|
6
|
-
from .simple import Identity, Scale, Translate
|
|
7
|
-
from .map_axis import MapAxis
|
|
8
4
|
from .bijection import Bijection
|
|
9
|
-
from .project_axis import ProjectAxis
|
|
10
5
|
from .by_dimension import ByDimension, SubTransform
|
|
11
|
-
from .
|
|
6
|
+
from .grid import GridInterpolation
|
|
7
|
+
from .map_axis import MapAxis
|
|
12
8
|
from .moving_least_squares import MovingLeastSquares
|
|
9
|
+
from .project_axis import ProjectAxis
|
|
10
|
+
from .reflection import Reflect
|
|
11
|
+
from .simple import Identity, Scale, Translate
|
|
13
12
|
from .thinplate import ThinPlateSplines
|
|
13
|
+
from .vector_field import Coordinates, Displacements
|
|
14
14
|
|
|
15
15
|
__all__ = [
|
|
16
16
|
"Affine",
|
|
17
|
+
"Bijection",
|
|
18
|
+
"ByDimension",
|
|
19
|
+
"Coordinates",
|
|
20
|
+
"Displacements",
|
|
17
21
|
"GridInterpolation",
|
|
18
22
|
"Identity",
|
|
23
|
+
"MapAxis",
|
|
24
|
+
"MovingLeastSquares",
|
|
19
25
|
"ProjectAxis",
|
|
20
26
|
"Reflect",
|
|
21
27
|
"Scale",
|
|
22
|
-
"Translate",
|
|
23
|
-
"MapAxis",
|
|
24
|
-
"Bijection",
|
|
25
|
-
"ByDimension",
|
|
26
28
|
"SubTransform",
|
|
27
|
-
"Coordinates",
|
|
28
|
-
"Displacements",
|
|
29
|
-
"MovingLeastSquares",
|
|
30
29
|
"ThinPlateSplines",
|
|
30
|
+
"Translate",
|
|
31
31
|
]
|
|
File without changes
|
|
@@ -3,17 +3,17 @@ Simple transformations like rigid translation and scaling.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from copy import copy
|
|
6
|
-
from typing import Self
|
|
7
6
|
from types import ModuleType
|
|
8
|
-
|
|
9
|
-
from numpy.typing import ArrayLike
|
|
7
|
+
from typing import Self
|
|
10
8
|
|
|
11
9
|
from array_api_compat import array_namespace
|
|
12
10
|
from array_api_compat import device as xp_device
|
|
11
|
+
from numpy.typing import ArrayLike
|
|
12
|
+
|
|
13
13
|
from ..base import Transform
|
|
14
|
+
from ..transforms.affine import Affine
|
|
14
15
|
from ..types import NDims
|
|
15
16
|
from ..util import ArrayT, as_floats, join_strs
|
|
16
|
-
from ..transforms.affine import Affine
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class Identity(Transform[ArrayT]):
|