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

Commit43c8913

Browse files
committed
Add non 2D paths wip [skip ci]
1 parent04bda58 commit43c8913

File tree

2 files changed

+88
-25
lines changed

2 files changed

+88
-25
lines changed

‎lib/matplotlib/path.py

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,13 @@ class Path:
9797
CLOSEPOLY:1}
9898

9999
def__init__(self,vertices,codes=None,_interpolation_steps=1,
100-
closed=False,readonly=False):
100+
closed=False,readonly=False,dims=2):
101101
"""
102102
Create a new path with the given vertices and codes.
103103
104104
Parameters
105105
----------
106-
vertices : (N,2) array-like
106+
vertices : (N,dims) array-like
107107
The path vertices, as an array, masked array or sequence of pairs.
108108
Masked values, if any, will be converted to NaNs, which are then
109109
handled correctly by the Agg PathIterator and other consumers of
@@ -125,9 +125,14 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1,
125125
readonly : bool, optional
126126
Makes the path behave in an immutable way and sets the vertices
127127
and codes as read-only arrays.
128+
dims : int, optional
128129
"""
130+
ifdims<=1:
131+
raiseValueError("Path must be at least 2D")
132+
self._dims=dims
133+
129134
vertices=_to_unmasked_float_array(vertices)
130-
_api.check_shape((None,2),vertices=vertices)
135+
_api.check_shape((None,dims),vertices=vertices)
131136

132137
ifcodesisnotNone:
133138
codes=np.asarray(codes,self.code_type)
@@ -178,6 +183,7 @@ def _fast_from_codes_and_verts(cls, verts, codes, internals_from=None):
178183
pth._vertices=_to_unmasked_float_array(verts)
179184
pth._codes=codes
180185
pth._readonly=False
186+
pth._dims=pth._vertices.shape[1]
181187
ifinternals_fromisnotNone:
182188
pth._should_simplify=internals_from._should_simplify
183189
pth._simplify_threshold=internals_from._simplify_threshold
@@ -210,13 +216,15 @@ def _update_values(self):
210216

211217
@property
212218
defvertices(self):
213-
"""The vertices of the `Path` as an (N,2) array."""
219+
"""The vertices of the `Path` as an (N,dims) array."""
214220
returnself._vertices
215221

216222
@vertices.setter
217223
defvertices(self,vertices):
218224
ifself._readonly:
219225
raiseAttributeError("Can't set vertices on a readonly Path")
226+
ifnot_api.check_shape((None,self._dims),vertices=vertices):
227+
raiseValueError("Vertices shape does not match path dimensions")
220228
self._vertices=vertices
221229
self._update_values()
222230

@@ -239,6 +247,26 @@ def codes(self, codes):
239247
self._codes=codes
240248
self._update_values()
241249

250+
@property
251+
defdims(self):
252+
"""
253+
The dimensions of vertices in the `Path`.
254+
"""
255+
returnself._dims
256+
257+
@dims.setter
258+
defdims(self,dims):
259+
ifdims<=2:
260+
raiseValueError("Path must be at least 2D")
261+
262+
ifdims<self._dims:
263+
self._vertices=self._vertices[:, :dims]
264+
elifdims>self._dims:
265+
self._vertices=np.pad(self._vertices,
266+
((0,0), (0,dims-self._dims)),
267+
mode='constant',constant_values=np.nan)
268+
self._dims=dims
269+
242270
@property
243271
defsimplify_threshold(self):
244272
"""
@@ -298,17 +326,17 @@ def make_compound_path_from_polys(cls, XY):
298326
299327
Parameters
300328
----------
301-
XY : (numpolys, numsides,2) array
329+
XY : (numpolys, numsides,dims) array
302330
"""
303331
# for each poly: 1 for the MOVETO, (numsides-1) for the LINETO, 1 for
304332
# the CLOSEPOLY; the vert for the closepoly is ignored but we still
305333
# need it to keep the codes aligned with the vertices
306-
numpolys,numsides,two=XY.shape
307-
iftwo!=2:
308-
raiseValueError("The third dimension of 'XY' must be 2")
334+
numpolys,numsides,dims=XY.shape
335+
ifdims<2:
336+
raiseValueError("The third dimension of 'XY' must beat least2")
309337
stride=numsides+1
310338
nverts=numpolys*stride
311-
verts=np.zeros((nverts,2))
339+
verts=np.zeros((nverts,dims))
312340
codes=np.full(nverts,cls.LINETO,dtype=cls.code_type)
313341
codes[0::stride]=cls.MOVETO
314342
codes[numsides::stride]=cls.CLOSEPOLY
@@ -323,6 +351,9 @@ def make_compound_path(cls, *args):
323351
"""
324352
ifnotargs:
325353
returnPath(np.empty([0,2],dtype=np.float32))
354+
ifnotall([path._dims!=args[0]._dimsforpathinargs]):
355+
raiseValueError("Paths provided must be the same dimension")
356+
326357
vertices=np.concatenate([path.verticesforpathinargs])
327358
codes=np.empty(len(vertices),dtype=cls.code_type)
328359
i=0
@@ -338,6 +369,16 @@ def make_compound_path(cls, *args):
338369
not_stop_mask=codes!=cls.STOP# Remove STOPs, as internal STOPs are a bug.
339370
returncls(vertices[not_stop_mask],codes[not_stop_mask])
340371

372+
@classmethod
373+
def_project_to_2d(cls,path,transform=None):
374+
iftransformisnotNone:
375+
path=transform.transform_path(path)
376+
377+
ifpath._dims>2:
378+
path=Path._fast_from_codes_and_verts(path.vertices[:,2],path.codes,
379+
path)
380+
returnpath
381+
341382
def__repr__(self):
342383
returnf"Path({self.vertices!r},{self.codes!r})"
343384

@@ -478,6 +519,10 @@ def cleaned(self, transform=None, remove_nans=False, clip=None,
478519
--------
479520
Path.iter_segments : for details of the keyword arguments.
480521
"""
522+
# Not implemented for non 2D
523+
ifself._dims!=2:
524+
returnself
525+
481526
vertices,codes=_path.cleanup_path(
482527
self,transform,remove_nans,clip,snap,stroke_width,simplify,
483528
curves,sketch)
@@ -497,7 +542,7 @@ def transformed(self, transform):
497542
automatically update when the transform changes.
498543
"""
499544
returnPath(transform.transform(self.vertices),self.codes,
500-
self._interpolation_steps)
545+
self._interpolation_steps,dims=transform.output_dims)
501546

502547
defcontains_point(self,point,transform=None,radius=0.0):
503548
"""
@@ -540,14 +585,22 @@ def contains_point(self, point, transform=None, radius=0.0):
540585
"""
541586
iftransformisnotNone:
542587
transform=transform.frozen()
588+
589+
# Transform the path, and then toss out the z dimension
590+
ifself.dims>2:
591+
pth=Path._project_to_2d(self,transform)
592+
transform=None
593+
543594
# `point_in_path` does not handle nonlinear transforms, so we
544595
# transform the path ourselves. If *transform* is affine, letting
545596
# `point_in_path` handle the transform avoids allocating an extra
546597
# buffer.
547-
iftransformandnottransform.is_affine:
598+
eliftransformandnottransform.is_affine:
548599
self=transform.transform_path(self)
600+
pth=self
549601
transform=None
550-
return_path.point_in_path(point[0],point[1],radius,self,transform)
602+
603+
return_path.point_in_path(point[0],point[1],radius,pth,transform)
551604

552605
defcontains_points(self,points,transform=None,radius=0.0):
553606
"""
@@ -590,7 +643,11 @@ def contains_points(self, points, transform=None, radius=0.0):
590643
"""
591644
iftransformisnotNone:
592645
transform=transform.frozen()
593-
result=_path.points_in_path(points,radius,self,transform)
646+
pth=self
647+
ifself._dims>2:
648+
pth=Path._project_to_2d(self,transform)
649+
transform=None
650+
result=_path.points_in_path(points,radius,pth,transform)
594651
returnresult.astype('bool')
595652

596653
defcontains_path(self,path,transform=None):
@@ -602,7 +659,15 @@ def contains_path(self, path, transform=None):
602659
"""
603660
iftransformisnotNone:
604661
transform=transform.frozen()
605-
return_path.path_in_path(self,None,path,transform)
662+
663+
a_pth=Path._project_to_2d(self,None)
664+
ifpath._dims>2:
665+
b_pth=Path._project_to_2d(path,transform)
666+
transform=None
667+
else:
668+
b_pth=path
669+
670+
return_path.path_in_path(a_pth,None,b_pth,transform)
606671

607672
defget_extents(self,transform=None,**kwargs):
608673
"""
@@ -652,7 +717,9 @@ def intersects_path(self, other, filled=True):
652717
If *filled* is True, then this also returns True if one path completely
653718
encloses the other (i.e., the paths are treated as filled).
654719
"""
655-
return_path.path_intersects_path(self,other,filled)
720+
a=Path._project_to_2d(self)
721+
b=Path._project_to_2d(other)
722+
return_path.path_intersects_path(a,b,filled)
656723

657724
defintersects_bbox(self,bbox,filled=True):
658725
"""
@@ -663,8 +730,9 @@ def intersects_bbox(self, bbox, filled=True):
663730
664731
The bounding box is always considered filled.
665732
"""
733+
pth=Path._project_to_2d(self)
666734
return_path.path_intersects_rectangle(
667-
self,bbox.x0,bbox.y0,bbox.x1,bbox.y1,filled)
735+
pth,bbox.x0,bbox.y0,bbox.x1,bbox.y1,filled)
668736

669737
definterpolated(self,steps):
670738
"""
@@ -683,7 +751,7 @@ def interpolated(self, steps):
683751
new_codes[0::steps]=codes
684752
else:
685753
new_codes=None
686-
returnPath(vertices,new_codes)
754+
returnPath(vertices,new_codes,dims=vertices.shape[1])
687755

688756
defto_polygons(self,transform=None,width=0,height=0,closed_only=True):
689757
"""

‎lib/matplotlib/transforms.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,8 +1608,6 @@ def transform_path(self, path):
16081608
In some cases, this transform may insert curves into the path
16091609
that began as line segments.
16101610
"""
1611-
ifself.input_dims!=2orself.output_dims!=2:
1612-
raiseNotImplementedError('Only defined in 2D')
16131611
returnself.transform_path_affine(self.transform_path_non_affine(path))
16141612

16151613
deftransform_path_affine(self,path):
@@ -1620,8 +1618,6 @@ def transform_path_affine(self, path):
16201618
``transform_path(path)`` is equivalent to
16211619
``transform_path_affine(transform_path_non_affine(values))``.
16221620
"""
1623-
ifself.input_dims!=2orself.output_dims!=2:
1624-
raiseNotImplementedError('Only defined in 2D')
16251621
returnself.get_affine().transform_path_affine(path)
16261622

16271623
deftransform_path_non_affine(self,path):
@@ -1632,10 +1628,9 @@ def transform_path_non_affine(self, path):
16321628
``transform_path(path)`` is equivalent to
16331629
``transform_path_affine(transform_path_non_affine(values))``.
16341630
"""
1635-
ifself.input_dims!=2orself.output_dims!=2:
1636-
raiseNotImplementedError('Only defined in 2D')
16371631
x=self.transform_non_affine(path.vertices)
1638-
returnPath._fast_from_codes_and_verts(x,path.codes,path)
1632+
returnPath._fast_from_codes_and_verts(x,path.codes,path,
1633+
dims=self.output_dims)
16391634

16401635
deftransform_angles(self,angles,pts,radians=False,pushoff=1e-5):
16411636
"""
@@ -1817,7 +1812,7 @@ def transform_path(self, path):
18171812
deftransform_path_affine(self,path):
18181813
# docstring inherited
18191814
returnPath(self.transform_affine(path.vertices),
1820-
path.codes,path._interpolation_steps)
1815+
path.codes,path._interpolation_steps,dims=self.output_dims)
18211816

18221817
deftransform_path_non_affine(self,path):
18231818
# docstring inherited

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp