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

Commit98f6eb2

Browse files
committed
Merge pull request#731 from pelson/plot_limit_with_transform
Plot limit with transform
2 parents22e6070 +4b0fbb5 commit98f6eb2

File tree

9 files changed

+745
-239
lines changed

9 files changed

+745
-239
lines changed

‎doc/api/api_changes.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,54 @@ Changes in 1.2.x
7272
original keyword arguments will override any value provided by
7373
*capthick*.
7474

75+
* Transform subclassing behaviour is now subtly changed. If your transform
76+
implements a non-affine transformation, then it should override the
77+
``transform_non_affine`` method, rather than the generic ``transform`` method.
78+
Previously transforms would define ``transform`` and then copy the
79+
method into ``transform_non_affine``:
80+
81+
class MyTransform(mtrans.Transform):
82+
def transform(self, xy):
83+
...
84+
transform_non_affine = transform
85+
86+
This approach will no longer function correctly and should be changed to:
87+
88+
class MyTransform(mtrans.Transform):
89+
def transform_non_affine(self, xy):
90+
...
91+
92+
* Artists no longer have ``x_isdata`` or ``y_isdata`` attributes; instead
93+
any artist's transform can be interrogated with
94+
``artist_instance.get_transform().contains_branch(ax.transData)``
95+
96+
* Lines added to an axes now take into account their transform when updating the
97+
data and view limits. This means transforms can now be used as a pre-transform.
98+
For instance:
99+
100+
>>>import matplotlib.pyplotas plt
101+
>>>import matplotlib.transformsas mtrans
102+
>>>ax= plt.axes()
103+
>>>ax.plot(range(10),transform=mtrans.Affine2D().scale(10)+ ax.transData)
104+
>>>print(ax.viewLim)
105+
Bbox('array([[ 0., 0.],\n [ 90., 90.]])')
106+
107+
* One can now easily get a transform which goes from one transform's coordinate system
108+
to another, in an optimized way, using the new subtract method on a transform. For instance,
109+
to go from data coordinates to axes coordinates::
110+
111+
>>> import matplotlib.pyplot as plt
112+
>>> ax = plt.axes()
113+
>>> data2ax = ax.transData - ax.transAxes
114+
>>> print(ax.transData.depth, ax.transAxes.depth)
115+
3, 1
116+
>>> print(data2ax.depth)
117+
2
118+
119+
for versions before 1.2 this could only be achieved in a sub-optimal way, using
120+
``ax.transData + ax.transAxes.inverted()`` (depth is a new concept, but had it existed
121+
it would return 4 for this example).
122+
75123
Changes in 1.1.x
76124
================
77125

‎lib/matplotlib/artist.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ def __init__(self):
101101
self._remove_method=None
102102
self._url=None
103103
self._gid=None
104-
self.x_isdata=True# False to avoid updating Axes.dataLim with x
105-
self.y_isdata=True# with y
106104
self._snap=None
107105

108106
defremove(self):

‎lib/matplotlib/axes.py

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,17 +1461,52 @@ def add_line(self, line):
14611461

14621462
self._update_line_limits(line)
14631463
ifnotline.get_label():
1464-
line.set_label('_line%d'%len(self.lines))
1464+
line.set_label('_line%d'%len(self.lines))
14651465
self.lines.append(line)
14661466
line._remove_method=lambdah:self.lines.remove(h)
14671467
returnline
14681468

14691469
def_update_line_limits(self,line):
1470-
p=line.get_path()
1471-
ifp.vertices.size>0:
1472-
self.dataLim.update_from_path(p,self.ignore_existing_data_limits,
1473-
updatex=line.x_isdata,
1474-
updatey=line.y_isdata)
1470+
"""Figures out the data limit of the given line, updating self.dataLim."""
1471+
path=line.get_path()
1472+
ifpath.vertices.size==0:
1473+
return
1474+
1475+
line_trans=line.get_transform()
1476+
1477+
ifline_trans==self.transData:
1478+
data_path=path
1479+
1480+
elifany(line_trans.contains_branch_seperately(self.transData)):
1481+
# identify the transform to go from line's coordinates
1482+
# to data coordinates
1483+
trans_to_data=line_trans-self.transData
1484+
1485+
# if transData is affine we can use the cached non-affine component
1486+
# of line's path. (since the non-affine part of line_trans is
1487+
# entirely encapsulated in trans_to_data).
1488+
ifself.transData.is_affine:
1489+
line_trans_path=line._get_transformed_path()
1490+
na_path,_=line_trans_path.get_transformed_path_and_affine()
1491+
data_path=trans_to_data.transform_path_affine(na_path)
1492+
else:
1493+
data_path=trans_to_data.transform_path(path)
1494+
else:
1495+
# for backwards compatibility we update the dataLim with the
1496+
# coordinate range of the given path, even though the coordinate
1497+
# systems are completely different. This may occur in situations
1498+
# such as when ax.transAxes is passed through for absolute
1499+
# positioning.
1500+
data_path=path
1501+
1502+
ifdata_path.vertices.size>0:
1503+
updatex,updatey=line_trans.contains_branch_seperately(
1504+
self.transData
1505+
)
1506+
self.dataLim.update_from_path(data_path,
1507+
self.ignore_existing_data_limits,
1508+
updatex=updatex,
1509+
updatey=updatey)
14751510
self.ignore_existing_data_limits=False
14761511

14771512
defadd_patch(self,p):
@@ -1507,11 +1542,14 @@ def _update_patch_limits(self, patch):
15071542
ifvertices.size>0:
15081543
xys=patch.get_patch_transform().transform(vertices)
15091544
ifpatch.get_data_transform()!=self.transData:
1510-
transform= (patch.get_data_transform()+
1511-
self.transData.inverted())
1512-
xys=transform.transform(xys)
1513-
self.update_datalim(xys,updatex=patch.x_isdata,
1514-
updatey=patch.y_isdata)
1545+
patch_to_data= (patch.get_data_transform()-
1546+
self.transData)
1547+
xys=patch_to_data.transform(xys)
1548+
1549+
updatex,updatey=patch.get_transform().\
1550+
contains_branch_seperately(self.transData)
1551+
self.update_datalim(xys,updatex=updatex,
1552+
updatey=updatey)
15151553

15161554

15171555
defadd_table(self,tab):
@@ -1599,13 +1637,13 @@ def _process_unit_info(self, xdata=None, ydata=None, kwargs=None):
15991637
ifxdataisnotNone:
16001638
# we only need to update if there is nothing set yet.
16011639
ifnotself.xaxis.have_units():
1602-
self.xaxis.update_units(xdata)
1640+
self.xaxis.update_units(xdata)
16031641
#print '\tset from xdata', self.xaxis.units
16041642

16051643
ifydataisnotNone:
16061644
# we only need to update if there is nothing set yet.
16071645
ifnotself.yaxis.have_units():
1608-
self.yaxis.update_units(ydata)
1646+
self.yaxis.update_units(ydata)
16091647
#print '\tset from ydata', self.yaxis.units
16101648

16111649
# process kwargs 2nd since these will override default units
@@ -3424,7 +3462,6 @@ def axhline(self, y=0, xmin=0, xmax=1, **kwargs):
34243462
trans=mtransforms.blended_transform_factory(
34253463
self.transAxes,self.transData)
34263464
l=mlines.Line2D([xmin,xmax], [y,y],transform=trans,**kwargs)
3427-
l.x_isdata=False
34283465
self.add_line(l)
34293466
self.autoscale_view(scalex=False,scaley=scaley)
34303467
returnl
@@ -3489,7 +3526,6 @@ def axvline(self, x=0, ymin=0, ymax=1, **kwargs):
34893526
trans=mtransforms.blended_transform_factory(
34903527
self.transData,self.transAxes)
34913528
l=mlines.Line2D([x,x], [ymin,ymax] ,transform=trans,**kwargs)
3492-
l.y_isdata=False
34933529
self.add_line(l)
34943530
self.autoscale_view(scalex=scalex,scaley=False)
34953531
returnl
@@ -3546,7 +3582,6 @@ def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs):
35463582
verts= (xmin,ymin), (xmin,ymax), (xmax,ymax), (xmax,ymin)
35473583
p=mpatches.Polygon(verts,**kwargs)
35483584
p.set_transform(trans)
3549-
p.x_isdata=False
35503585
self.add_patch(p)
35513586
self.autoscale_view(scalex=False)
35523587
returnp
@@ -3603,7 +3638,6 @@ def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs):
36033638
verts= [(xmin,ymin), (xmin,ymax), (xmax,ymax), (xmax,ymin)]
36043639
p=mpatches.Polygon(verts,**kwargs)
36053640
p.set_transform(trans)
3606-
p.y_isdata=False
36073641
self.add_patch(p)
36083642
self.autoscale_view(scaley=False)
36093643
returnp
@@ -3909,7 +3943,6 @@ def plot(self, *args, **kwargs):
39093943
self.add_line(line)
39103944
lines.append(line)
39113945

3912-
39133946
self.autoscale_view(scalex=scalex,scaley=scaley)
39143947
returnlines
39153948

‎lib/matplotlib/lines.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
# TODO: expose cap and join style attrs
77
from __future__importdivision,print_function
88

9+
importwarnings
10+
911
importnumpyasnp
1012
fromnumpyimportma
1113
frommatplotlibimportverbose
@@ -249,17 +251,15 @@ def contains(self, mouseevent):
249251
iflen(self._xy)==0:returnFalse,{}
250252

251253
# Convert points to pixels
252-
ifself._transformed_pathisNone:
253-
self._transform_path()
254-
path,affine=self._transformed_path.get_transformed_path_and_affine()
254+
path,affine=self._get_transformed_path().get_transformed_path_and_affine()
255255
path=affine.transform_path(path)
256256
xy=path.vertices
257257
xt=xy[:,0]
258258
yt=xy[:,1]
259259

260260
# Convert pick radius from points to pixels
261-
ifself.figure==None:
262-
warning.warn('no figure set when check if mouse is on line')
261+
ifself.figureisNone:
262+
warnings.warn('no figure set when check if mouse is on line')
263263
pixels=self.pickradius
264264
else:
265265
pixels=self.figure.dpi/72.*self.pickradius
@@ -446,13 +446,26 @@ def recache(self, always=False):
446446
self._invalidy=False
447447

448448
def_transform_path(self,subslice=None):
449+
"""
450+
Puts a TransformedPath instance at self._transformed_path,
451+
all invalidation of the transform is then handled by the
452+
TransformedPath instance.
453+
"""
449454
# Masked arrays are now handled by the Path class itself
450455
ifsubsliceisnotNone:
451456
_path=Path(self._xy[subslice,:])
452457
else:
453458
_path=self._path
454459
self._transformed_path=TransformedPath(_path,self.get_transform())
455460

461+
def_get_transformed_path(self):
462+
"""
463+
Return the :class:`~matplotlib.transforms.TransformedPath` instance
464+
of this line.
465+
"""
466+
ifself._transformed_pathisNone:
467+
self._transform_path()
468+
returnself._transformed_path
456469

457470
defset_transform(self,t):
458471
"""
@@ -482,8 +495,8 @@ def draw(self, renderer):
482495
subslice=slice(max(i0-1,0),i1+1)
483496
self.ind_offset=subslice.start
484497
self._transform_path(subslice)
485-
ifself._transformed_pathisNone:
486-
self._transform_path()
498+
499+
transformed_path=self._get_transformed_path()
487500

488501
ifnotself.get_visible():return
489502

@@ -507,7 +520,7 @@ def draw(self, renderer):
507520

508521
funcname=self._lineStyles.get(self._linestyle,'_draw_nothing')
509522
iffuncname!='_draw_nothing':
510-
tpath,affine=self._transformed_path.get_transformed_path_and_affine()
523+
tpath,affine=transformed_path.get_transformed_path_and_affine()
511524
iflen(tpath.vertices):
512525
self._lineFunc=getattr(self,funcname)
513526
funcname=self.drawStyles.get(self._drawstyle,'_draw_lines')
@@ -528,7 +541,7 @@ def draw(self, renderer):
528541
gc.set_linewidth(self._markeredgewidth)
529542
gc.set_alpha(self._alpha)
530543
marker=self._marker
531-
tpath,affine=self._transformed_path.get_transformed_points_and_affine()
544+
tpath,affine=transformed_path.get_transformed_points_and_affine()
532545
iflen(tpath.vertices):
533546
# subsample the markers if markevery is not None
534547
markevery=self.get_markevery()

‎lib/matplotlib/patches.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,21 @@ def get_transform(self):
167167
returnself.get_patch_transform()+artist.Artist.get_transform(self)
168168

169169
defget_data_transform(self):
170+
"""
171+
Return the :class:`~matplotlib.transforms.Transform` instance which
172+
maps data coordinates to physical coordinates.
173+
"""
170174
returnartist.Artist.get_transform(self)
171175

172176
defget_patch_transform(self):
177+
"""
178+
Return the :class:`~matplotlib.transforms.Transform` instance which
179+
takes patch coordinates to data coordinates.
180+
181+
For example, one may define a patch of a circle which represents a
182+
radius of 5 by providing coordinates for a unit circle, and a
183+
transform which scales the coordinates (the patch coordinate) by 5.
184+
"""
173185
returntransforms.IdentityTransform()
174186

175187
defget_antialiased(self):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp