Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf4de081

Browse files
committed
Add ability to blend any number of transforms
1 parent12e7d01 commitf4de081

File tree

3 files changed

+117
-92
lines changed

3 files changed

+117
-92
lines changed

‎lib/matplotlib/tests/test_transforms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ def test_str_transform():
850850
CompositeGenericTransform(
851851
CompositeGenericTransform(
852852
TransformWrapper(
853-
BlendedAffine2D(
853+
BlendedAffine(
854854
IdentityTransform(),
855855
IdentityTransform())),
856856
CompositeAffine2D(
@@ -864,7 +864,7 @@ def test_str_transform():
864864
CompositeGenericTransform(
865865
PolarAffine(
866866
TransformWrapper(
867-
BlendedAffine2D(
867+
BlendedAffine(
868868
IdentityTransform(),
869869
IdentityTransform())),
870870
LockableBbox(

‎lib/matplotlib/transforms.py

Lines changed: 107 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,182 +2216,208 @@ def inverted(self):
22162216

22172217

22182218
class_BlendedMixin:
2219-
"""Common methods for `BlendedGenericTransform` and `BlendedAffine2D`."""
2219+
"""Common methods for `BlendedGenericTransform` and `BlendedAffine`."""
22202220

22212221
def__eq__(self,other):
2222-
ifisinstance(other, (BlendedAffine2D,BlendedGenericTransform)):
2223-
return (self._x==other._x)and (self._y==other._y)
2224-
elifself._x==self._y:
2225-
returnself._x==other
2222+
2223+
num_transforms=len(self._transforms)
2224+
2225+
if (isinstance(other, (BlendedGenericTransform,BlendedAffine))
2226+
andnum_transforms==len(other._transforms)):
2227+
returnall(self._transforms[i]==other._transforms[i]
2228+
foriinrange(num_transforms))
22262229
else:
22272230
returnNotImplemented
22282231

22292232
defcontains_branch_seperately(self,transform):
2230-
return (self._x.contains_branch(transform),
2231-
self._y.contains_branch(transform))
2233+
returntuple(branch.contains_branch(transform)forbranchinself._transforms)
22322234

2233-
__str__=_make_str_method("_x","_y")
2235+
def__str__(self):
2236+
indent=functools.partial(textwrap.indent,prefix=" "*4)
2237+
return (
2238+
type(self).__name__+"("
2239+
+",".join([*(indent("\n"+transform.__str__())
2240+
fortransforminself._transforms)])
2241+
+")")
22342242

22352243

22362244
classBlendedGenericTransform(_BlendedMixin,Transform):
22372245
"""
2238-
A "blended" transform uses one transform for the *x*-direction, and
2239-
another transform for the *y*-direction.
2246+
A "blended" transform uses one transform for each direction
22402247
2241-
This "generic" version can handle any given childtransform in the
2242-
*x*- and *y*-directions.
2248+
This "generic" version can handle anynumber ofgiven childtransforms, each
2249+
handling a different axis.
22432250
"""
2244-
input_dims=2
2245-
output_dims=2
22462251
is_separable=True
22472252
pass_through=True
22482253

2249-
def__init__(self,x_transform,y_transform,**kwargs):
2254+
def__init__(self,*args,**kwargs):
22502255
"""
2251-
Create a new "blended" transform using *x_transform* to transform the
2252-
*x*-axis and *y_transform* to transform the *y*-axis.
2256+
Create a new "blended" transform, with the first argument providing
2257+
a transform for the *x*-axis, the second argument providing a transform
2258+
for the *y*-axis, etc.
22532259
22542260
You will generally not call this constructor directly but use the
22552261
`blended_transform_factory` function instead, which can determine
22562262
automatically which kind of blended transform to create.
22572263
"""
2264+
self.input_dims=self.output_dims=len(args)
2265+
2266+
foriinrange(self.input_dims):
2267+
transform=args[i]
2268+
iftransform.input_dims>1andtransform.input_dims<=i:
2269+
raiseTypeError("Invalid transform provided to"
2270+
"`BlendedGenericTransform`")
2271+
22582272
Transform.__init__(self,**kwargs)
2259-
self._x=x_transform
2260-
self._y=y_transform
2261-
self.set_children(x_transform,y_transform)
2273+
self.set_children(*args)
2274+
self._transforms=args
22622275
self._affine=None
22632276

22642277
@property
22652278
defdepth(self):
2266-
returnmax(self._x.depth,self._y.depth)
2279+
returnmax(transform.depthfortransforminself._transforms)
22672280

22682281
defcontains_branch(self,other):
22692282
# A blended transform cannot possibly contain a branch from two
22702283
# different transforms.
22712284
returnFalse
22722285

2273-
is_affine=property(lambdaself:self._x.is_affineandself._y.is_affine)
2274-
has_inverse=property(
2275-
lambdaself:self._x.has_inverseandself._y.has_inverse)
2286+
is_affine=property(lambdaself:all(transform.is_affine
2287+
fortransforminself._transforms))
2288+
has_inverse=property(lambdaself:all(transform.has_inverse
2289+
fortransforminself._transforms))
22762290

22772291
deffrozen(self):
22782292
# docstring inherited
2279-
returnblended_transform_factory(self._x.frozen(),self._y.frozen())
2293+
returnblended_transform_factory(*(transform.frozen()
2294+
fortransforminself._transforms))
22802295

22812296
@_api.rename_parameter("3.8","points","values")
22822297
deftransform_non_affine(self,values):
22832298
# docstring inherited
2284-
ifself._x.is_affineandself._y.is_affine:
2299+
ifself.is_affine:
22852300
returnvalues
2286-
x=self._x
2287-
y=self._y
22882301

2289-
ifx==yandx.input_dims==2:
2290-
returnx.transform_non_affine(values)
2302+
ifall(transform==self._transforms[0]
2303+
fortransforminself._transforms)andself.input_dims>=2:
2304+
returnself._transforms[0].transform_non_affine(values)
22912305

2292-
ifx.input_dims==2:
2293-
x_points=x.transform_non_affine(values)[:,0:1]
2294-
else:
2295-
x_points=x.transform_non_affine(values[:,0])
2296-
x_points=x_points.reshape((len(x_points),1))
2306+
all_points= []
2307+
masked=False
22972308

2298-
ify.input_dims==2:
2299-
y_points=y.transform_non_affine(values)[:,1:]
2300-
else:
2301-
y_points=y.transform_non_affine(values[:,1])
2302-
y_points=y_points.reshape((len(y_points),1))
2309+
fordiminrange(self.input_dims):
2310+
transform=self._transforms[dim]
2311+
iftransform.input_dims==1:
2312+
points=transform.transform_non_affine(values[:,dim])
2313+
points=points.reshape((len(points),1))
2314+
else:
2315+
points=transform.transform_non_affine(values)[:,dim:dim+1]
2316+
2317+
masked=maskedorisinstance(points,np.ma.MaskedArray)
2318+
all_points.append(points)
23032319

2304-
if (isinstance(x_points,np.ma.MaskedArray)or
2305-
isinstance(y_points,np.ma.MaskedArray)):
2306-
returnnp.ma.concatenate((x_points,y_points),1)
2320+
ifmasked:
2321+
returnnp.ma.concatenate(tuple(all_points),1)
23072322
else:
2308-
returnnp.concatenate((x_points,y_points),1)
2323+
returnnp.concatenate(tuple(all_points),1)
23092324

23102325
definverted(self):
23112326
# docstring inherited
2312-
returnBlendedGenericTransform(self._x.inverted(),self._y.inverted())
2327+
returnBlendedGenericTransform(*(transform.inverted()
2328+
fortransforminself._transforms))
23132329

23142330
defget_affine(self):
23152331
# docstring inherited
23162332
ifself._invalidorself._affineisNone:
2317-
ifself._x==self._y:
2318-
self._affine=self._x.get_affine()
2333+
ifall(transform==self._transforms[0]fortransforminself._transforms):
2334+
self._affine=self._transforms[0].get_affine()
23192335
else:
2320-
x_mtx=self._x.get_affine().get_matrix()
2321-
y_mtx=self._y.get_affine().get_matrix()
2322-
# We already know the transforms are separable, so we can skip
2323-
# setting b and c to zero.
2324-
mtx=np.array([x_mtx[0],y_mtx[1], [0.0,0.0,1.0]])
2325-
self._affine=Affine2D(mtx)
2336+
mtx=np.identity(self.input_dims+1)
2337+
foriinrange(self.input_dims):
2338+
transform=self._transforms[i]
2339+
iftransform.output_dims>1:
2340+
mtx[i]=transform.get_affine().get_matrix()[i]
2341+
2342+
self._affine=_affine_factory(mtx,dims=self.input_dims)
23262343
self._invalid=0
23272344
returnself._affine
23282345

23292346

2330-
classBlendedAffine2D(_BlendedMixin,Affine2DBase):
2347+
classBlendedAffine(_BlendedMixin,AffineImmutable):
23312348
"""
23322349
A "blended" transform uses one transform for the *x*-direction, and
23332350
another transform for the *y*-direction.
23342351
23352352
This version is an optimization for the case where both child
2336-
transforms are of type `Affine2DBase`.
2353+
transforms are of type `AffineImmutable`.
23372354
"""
23382355

23392356
is_separable=True
23402357

2341-
def__init__(self,x_transform,y_transform,**kwargs):
2358+
def__init__(self,*args,**kwargs):
23422359
"""
2343-
Create a new "blended" transform using *x_transform* to transform the
2344-
*x*-axis and *y_transform* to transform the *y*-axis.
2360+
Create a new "blended" transform, with the first argument providing
2361+
a transform for the *x*-axis, the second argument providing a transform
2362+
for the *y*-axis, etc.
23452363
2346-
Both *x_transform* and *y_transform*must be 2D affine transforms.
2364+
All provided transformsmust be affine transforms.
23472365
23482366
You will generally not call this constructor directly but use the
23492367
`blended_transform_factory` function instead, which can determine
23502368
automatically which kind of blended transform to create.
23512369
"""
2352-
is_affine=x_transform.is_affineandy_transform.is_affine
2353-
is_separable=x_transform.is_separableandy_transform.is_separable
2354-
is_correct=is_affineandis_separable
2355-
ifnotis_correct:
2356-
raiseValueError("Both *x_transform* and *y_transform* must be 2D "
2357-
"affine transforms")
2358-
23592370
Transform.__init__(self,**kwargs)
2360-
self._x=x_transform
2361-
self._y=y_transform
2362-
self.set_children(x_transform,y_transform)
2371+
AffineImmutable.__init__(self,**kwargs)
2372+
2373+
ifnotall(transform.is_affineandtransform.is_separable
2374+
fortransforminargs):
2375+
raiseValueError("Given transforms must be affine")
2376+
2377+
foriinrange(self.input_dims):
2378+
transform=args[i]
2379+
iftransform.input_dims>1andtransform.input_dims<=i:
2380+
raiseTypeError("Invalid transform provided to"
2381+
"`BlendedGenericTransform`")
2382+
2383+
self._transforms=args
2384+
self.set_children(*args)
23632385

2364-
Affine2DBase.__init__(self)
23652386
self._mtx=None
23662387

23672388
defget_matrix(self):
23682389
# docstring inherited
23692390
ifself._invalid:
2370-
ifself._x==self._y:
2371-
self._mtx=self._x.get_matrix()
2391+
ifall(transform==self._transforms[0]fortransforminself._transforms):
2392+
self._mtx=self._transforms[0].get_matrix()
23722393
else:
2373-
x_mtx=self._x.get_matrix()
2374-
y_mtx=self._y.get_matrix()
23752394
# We already know the transforms are separable, so we can skip
2376-
# setting b and c to zero.
2377-
self._mtx=np.array([x_mtx[0],y_mtx[1], [0.0,0.0,1.0]])
2395+
# setting non-diagonal values to zero.
2396+
self._mtx=np.array(
2397+
[self._transforms[i].get_affine().get_matrix()[i]
2398+
foriinrange(self.input_dims)]+
2399+
[[0.0]*self.input_dims+ [1.0]])
23782400
self._inverted=None
23792401
self._invalid=0
23802402
returnself._mtx
23812403

23822404

2383-
defblended_transform_factory(x_transform,y_transform):
2405+
@_api.deprecated("3.9",alternative="BlendedAffine")
2406+
classBlendedAffine2D(BlendedAffine):
2407+
pass
2408+
2409+
2410+
defblended_transform_factory(*args):
23842411
"""
23852412
Create a new "blended" transform using *x_transform* to transform
23862413
the *x*-axis and *y_transform* to transform the *y*-axis.
23872414
23882415
A faster version of the blended transform is returned for the case
23892416
where both child transforms are affine.
23902417
"""
2391-
if (isinstance(x_transform,Affine2DBase)and
2392-
isinstance(y_transform,Affine2DBase)):
2393-
returnBlendedAffine2D(x_transform,y_transform)
2394-
returnBlendedGenericTransform(x_transform,y_transform)
2418+
ifall(isinstance(transform,AffineImmutable)fortransforminargs):
2419+
returnBlendedAffine(*args)
2420+
returnBlendedGenericTransform(*args)
23952421

23962422

23972423
classCompositeGenericTransform(Transform):

‎lib/matplotlib/transforms.pyi

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,26 +258,25 @@ class _BlendedMixin:
258258
defcontains_branch_seperately(self,transform:Transform)->Sequence[bool]: ...
259259

260260
classBlendedGenericTransform(_BlendedMixin,Transform):
261-
input_dims:Literal[2]
262-
output_dims:Literal[2]
263261
pass_through:bool
264262
def__init__(
265-
self,x_transform:Transform,y_transform:Transform,**kwargs
263+
self,*args:Transform,**kwargs
266264
)->None: ...
267265
@property
268266
defdepth(self)->int: ...
269267
defcontains_branch(self,other:Transform)->Literal[False]: ...
270268
@property
271269
defis_affine(self)->bool: ...
272270

273-
classBlendedAffine2D(_BlendedMixin,Affine2DBase):
274-
def__init__(
275-
self,x_transform:Transform,y_transform:Transform,**kwargs
276-
)->None: ...
271+
classBlendedAffine(_BlendedMixin,AffineImmutable):
272+
def__init__(self,*args:Transform,**kwargs)->None: ...
273+
274+
classBlendedAffine2D(BlendedAffine):
275+
pass
277276

278277
defblended_transform_factory(
279-
x_transform:Transform,y_transform:Transform
280-
)->BlendedGenericTransform|BlendedAffine2D: ...
278+
*args:Transform
279+
)->BlendedGenericTransform|BlendedAffine: ...
281280

282281
classCompositeGenericTransform(Transform):
283282
pass_through:bool

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp