Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ae347ec

Browse files
committed
some support for path based clipping
svn path=/trunk/matplotlib/; revision=3092
1 parent 4633731 commit ae347ec

10 files changed

Lines changed: 312 additions & 227 deletions

File tree

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
2007-30-17 Preliminary support for clipping to paths agg - JDH
2+
13
2007-03-17 Text.set_text() accepts anything convertible with '%s' - EF
24

35
2007-03-14 Add masked-array support to hist. - EF

agg23/include/agg_path_storage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ namespace agg
112112
void curve3(double x_ctrl, double y_ctrl,
113113
double x_to, double y_to);
114114

115+
115116
void curve3_rel(double dx_ctrl, double dy_ctrl,
116117
double dx_to, double dy_to);
117118

examples/clippath_test.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from pylab import figure, show, nx
2+
from matplotlib.patches import RegularPolygon
3+
import matplotlib.agg as agg
4+
5+
fig = figure()
6+
ax = fig.add_subplot(111)
7+
t = nx.arange(0.0, 4.0, 0.01)
8+
s = 2*nx.sin(2*nx.pi*8*t)
9+
line, = ax.plot(t, s)
10+
line2, = ax.plot(t, 0.5*s)
11+
line3, = ax.plot(t, 4*s)
12+
markers, = ax.plot(t, 2*(nx.mlab.rand(len(t))-0.5), 'bo')
13+
path = agg.path_storage()
14+
poly = RegularPolygon( (2, 0.), numVertices=8, radius=1.5)
15+
#for i, xy in enumerate(ax.transData.seq_xy_tups(poly.get_verts())):
16+
for i, xy in enumerate(ax.transData.seq_xy_tups(poly.get_verts())):
17+
if i==0: path.move_to(*xy)
18+
else: path.line_to(*xy)
19+
path.close_polygon()
20+
line.set_clip_path(path)
21+
line2.set_clip_path(path)
22+
line3.set_clip_path(path)
23+
show()

lib/matplotlib/artist.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(self):
3636
self._animated = False
3737
self._alpha = 1.0
3838
self.clipbox = None
39+
self._clippath = None
3940
self._clipon = False
4041
self._lod = False
4142
self._label = ''
@@ -156,9 +157,20 @@ def set_clip_box(self, clipbox):
156157
ACCEPTS: a matplotlib.transform.Bbox instance
157158
"""
158159
self.clipbox = clipbox
159-
self._clipon = clipbox is not None
160+
self._clipon = clipbox is not None or self._clippath is not None
160161
self.pchanged()
161162

163+
def set_clip_path(self, path):
164+
"""
165+
Set the artist's clip path
166+
167+
ACCEPTS: an agg.path_storage instance
168+
"""
169+
self._clippath = path
170+
self._clipon = self.clipbox is not None or path is not None
171+
self.pchanged()
172+
173+
162174
def get_alpha(self):
163175
"""
164176
Return the alpha value used for blending - not supported on all
@@ -176,22 +188,34 @@ def get_animated(self):
176188

177189
def get_clip_on(self):
178190
'Return whether artist uses clipping'
179-
return self._clipon and self.clipbox is not None
191+
return self._clipon and (self.clipbox is not None or self._clippath is not None)
180192

181193
def get_clip_box(self):
182194
'Return artist clipbox'
183195
return self.clipbox
184196

197+
def get_clip_path(self):
198+
'Return artist clip path'
199+
return self._clippath
200+
185201
def set_clip_on(self, b):
186202
"""
187203
Set whether artist uses clipping
188204
189205
ACCEPTS: [True | False]
190206
"""
191207
self._clipon = b
192-
if not b: self.clipbox = None
208+
if not b:
209+
self.clipbox = None
210+
self._clippath = None
193211
self.pchanged()
194212

213+
def _set_gc_clip(self, gc):
214+
'set the clip properly for the gc'
215+
if self.clipbox is not None:
216+
gc.set_clip_rectangle(self.clipbox.get_bounds())
217+
gc.set_clip_path(self._clippath)
218+
195219
def draw(self, renderer, *args, **kwargs):
196220
'Derived classes drawing method'
197221
if not self.get_visible(): return

lib/matplotlib/axes.py

Lines changed: 82 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import numerix.ma as ma
1212

1313
import matplotlib.mlab
14+
import matplotlib.agg as agg
1415
import artist
1516
from artist import Artist, setp
1617
from axis import XAxis, YAxis
@@ -883,16 +884,8 @@ def get_child_artists(self):
883884
"""
884885
Return a list of artists the axes contains. Deprecated
885886
"""
886-
artists = [self.title, self.axesPatch, self.xaxis, self.yaxis]
887-
artists.extend(self.lines)
888-
artists.extend(self.patches)
889-
artists.extend(self.texts)
890-
artists.extend(self.collections)
891-
artists.extend(self.images)
892-
if self.legend_ is not None:
893-
artists.append(self.legend_)
894-
return silent_list('Artist', artists)
895-
887+
raise DeprecationWarning('Use get_children instead')
888+
896889
def get_frame(self):
897890
'Return the axes Rectangle frame'
898891
return self.axesPatch
@@ -4967,7 +4960,7 @@ def _set_lim_and_transforms(self):
49674960
Point( Value(1/4.*math.pi), Value(math.sqrt(2))))
49684961

49694962
self.transData = NonseparableTransformation(self.viewLim, self.bbox,
4970-
FuncXY(POLAR))
4963+
FuncXY(POLAR))
49714964
self.transAxes = get_bbox_transform(unit_bbox(), self.bbox)
49724965

49734966

@@ -5013,6 +5006,7 @@ def cla(self):
50135006
edgecolor=rcParams['axes.edgecolor'],
50145007
)
50155008

5009+
50165010
self.axesPatch.set_figure(self.figure)
50175011
self.axesPatch.set_transform(self.transData)
50185012
self.axesPatch.set_linewidth(rcParams['axes.linewidth'])
@@ -5035,16 +5029,35 @@ def cla(self):
50355029
self.set_thetagrids(angles)
50365030
self.set_rgrids(radii)
50375031

5032+
def get_children(self):
5033+
'return a list of child artists'
5034+
children = []
5035+
children.extend(self.rgridlines)
5036+
children.extend(self.rgridlabels)
5037+
children.extend(self.thetagridlines)
5038+
children.extend(self.thetagridlabels)
5039+
children.extend(self.lines)
5040+
children.extend(self.patches)
5041+
children.extend(self.texts)
5042+
children.extend(self.artists)
5043+
children.extend(self.images)
5044+
#if self.legend_ is not None:
5045+
# children.append(self.legend_)
5046+
children.extend(self.collections)
5047+
children.append(self.title)
5048+
children.append(self.axesPatch)
5049+
return children
5050+
5051+
5052+
def set_rmax(self, rmax):
5053+
self.rintv.set_bounds(0, rmax)
5054+
self.regrid(rmax)
5055+
50385056
def grid(self, b):
50395057
'Set the axes grids on or off; b is a boolean'
50405058
self._gridOn = b
50415059

5042-
def autoscale_view(self, scalex=True, scaley=True):
5043-
'set the view limits to include all the data in the axes'
5044-
self.rintd.set_bounds(0, self.get_rmax())
5045-
rmin, rmax = self.rlocator.autoscale()
5046-
self.rintv.set_bounds(rmin, rmax)
5047-
5060+
def regrid(self, rmax):
50485061
self.axesPatch.xy = zip(self.thetas, rmax*ones(self.RESOLUTION))
50495062
val = rmax*math.sqrt(2)
50505063
self.viewLim.intervaly().set_bounds(val, val)
@@ -5058,7 +5071,14 @@ def autoscale_view(self, scalex=True, scaley=True):
50585071
r = linspace(0, rmax, self.RESOLUTION)
50595072
for l in self.thetagridlines:
50605073
l.set_ydata(r)
5061-
5074+
5075+
def autoscale_view(self, scalex=True, scaley=True):
5076+
'set the view limits to include all the data in the axes'
5077+
self.rintd.set_bounds(0, self.get_rmax())
5078+
rmin, rmax = self.rlocator.autoscale()
5079+
self.rintv.set_bounds(rmin, rmax)
5080+
self.regrid(rmax)
5081+
50625082
def set_rgrids(self, radii, labels=None, angle=22.5, **kwargs):
50635083
"""
50645084
set the radial locations and labels of the r grids
@@ -5182,14 +5202,38 @@ def draw(self, renderer):
51825202
self.apply_aspect(1)
51835203
self.transData.freeze() # eval the lazy objects
51845204
self.transAxes.freeze() # eval the lazy objects
5205+
5206+
tverts = self.transData.seq_xy_tups(self.axesPatch.get_verts())
5207+
5208+
def make_clippath():
5209+
clippath = agg.path_storage()
5210+
for i, xy in enumerate(tverts):
5211+
if i==0: clippath.move_to(*xy)
5212+
else: clippath.line_to(*xy)
5213+
clippath.close_polygon()
5214+
return clippath
5215+
5216+
clippath = agg.path_storage()
5217+
for i, xy in enumerate(tverts):
5218+
if i==0: clippath.move_to(*xy)
5219+
else: clippath.line_to(*xy)
5220+
clippath.close_polygon()
5221+
51855222
#self._update_axes()
51865223
if self.axison:
51875224
if self._frameon: self.axesPatch.draw(renderer)
51885225

51895226
if self._gridOn:
51905227
for l in self.rgridlines+self.thetagridlines:
5228+
#l.set_clip_path(make_clippath())
5229+
#l.set_clip_path(clippath)
51915230
l.draw(renderer)
51925231

5232+
for line in self.lines:
5233+
#line.set_clip_path(make_clippath())
5234+
#line.set_clip_path(clippath)
5235+
pass
5236+
51935237
for t in self.thetagridlabels+self.rgridlabels:
51945238
t.draw(renderer)
51955239

@@ -5230,26 +5274,35 @@ def set_ylabel(self, ylabel, fontdict=None, **kwargs):
52305274
raise NotImplementedError('ylabel not defined for polar axes (yet)')
52315275

52325276

5233-
def set_xlim(self, v, emit=True):
5277+
def set_xlim(self, xmin=None, xmax=None, emit=True):
52345278
"""
5235-
SET_XLIM(v, emit=True)
5236-
5237-
A do nothing impl until we can figure out how to handle interaction
5279+
set the xlimits
52385280
ACCEPTS: len(2) sequence of floats
52395281
"""
5240-
#warnings.warn('Navigation set_ylim not implemented for polar')
5241-
self.viewLim.intervalx().set_bounds(*v)
5282+
if xmax is None and iterable(xmin):
5283+
xmin,xmax = xmin
5284+
5285+
old_xmin,old_xmax = self.get_xlim()
5286+
if xmin is None: xmin = old_xmin
5287+
if xmax is None: xmax = old_xmax
5288+
5289+
self.viewLim.intervalx().set_bounds(xmin, xmax)
52425290
if emit: self._send_xlim_event()
52435291

52445292

5245-
def set_ylim(self, v, emit=True):
5293+
def set_ylim(self, ymin=None, ymax=None, emit=True):
52465294
"""
5247-
SET_YLIM(v, emit=True)
5248-
5295+
set the ylimits
52495296
ACCEPTS: len(2) sequence of floats
52505297
"""
5251-
#warnings.warn('Navigation set_xlim not implemented for polar')
5252-
self.viewLim.intervaly().set_bounds(*v)
5298+
if ymax is None and iterable(ymin):
5299+
ymin,ymax = ymin
5300+
5301+
old_ymin,old_ymax = self.get_ylim()
5302+
if ymin is None: ymin = old_ymin
5303+
if ymax is None: ymax = old_ymax
5304+
5305+
self.viewLim.intervaly().set_bounds(ymin, ymax)
52535306
if emit: self._send_ylim_event()
52545307

52555308
def get_xscale(self):

lib/matplotlib/backend_bases.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ def __init__(self):
469469
self._antialiased = 1 # use 0,1 not True, False for extension code
470470
self._capstyle = 'butt'
471471
self._cliprect = None
472+
self._clippath = None
472473
self._dashes = None, None
473474
self._joinstyle = 'miter'
474475
self._linestyle = 'solid'
@@ -482,6 +483,7 @@ def copy_properties(self, gc):
482483
self._antialiased = gc._antialiased
483484
self._capstyle = gc._capstyle
484485
self._cliprect = gc._cliprect
486+
self._clippath = gc._clipath
485487
self._dashes = gc._dashes
486488
self._joinstyle = gc._joinstyle
487489
self._linestyle = gc._linestyle
@@ -512,6 +514,12 @@ def get_clip_rectangle(self):
512514
"""
513515
return self._cliprect
514516

517+
def get_clip_path(self):
518+
"""
519+
Return the clip path
520+
"""
521+
return self._clipath
522+
515523
def get_dashes(self):
516524
"""
517525
Return the dash information as an offset dashlist tuple The
@@ -579,6 +587,12 @@ def set_clip_rectangle(self, rectangle):
579587
"""
580588
self._cliprect = rectangle
581589

590+
def set_clip_path(self, path):
591+
"""
592+
Set the clip path
593+
"""
594+
self._clippath = path
595+
582596
def set_dashes(self, dash_offset, dash_list):
583597
"""
584598
Set the dash style for the gc.

lib/matplotlib/lines.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -379,13 +379,12 @@ def draw(self, renderer):
379379
if not self._visible: return
380380
self._newstyle = hasattr(renderer, 'draw_markers')
381381
gc = renderer.new_gc()
382+
self._set_gc_clip(gc)
383+
382384
gc.set_foreground(self._color)
383385
gc.set_antialiased(self._antialiased)
384386
gc.set_linewidth(self._linewidth)
385387
gc.set_alpha(self._alpha)
386-
if self.get_clip_on():
387-
gc.set_clip_rectangle(self.clipbox.get_bounds())
388-
389388
if self.is_dashed():
390389
cap = self._dashcapstyle
391390
join = self._dashjoinstyle
@@ -412,12 +411,15 @@ def draw(self, renderer):
412411
if self._segments is not None:
413412
for ii in self._segments:
414413
lineFunc(renderer, gc, xt[ii[0]:ii[1]], yt[ii[0]:ii[1]])
414+
415415
else:
416416
lineFunc(renderer, gc, xt, yt)
417417

418418

419419
if self._marker is not None:
420+
420421
gc = renderer.new_gc()
422+
self._set_gc_clip(gc)
421423
if (is_string_like(self._markeredgecolor) and
422424
self._markeredgecolor == 'auto'):
423425
if self._marker in self.filled_markers:
@@ -427,8 +429,6 @@ def draw(self, renderer):
427429
else:
428430
gc.set_foreground(self._markeredgecolor)
429431
gc.set_linewidth(self._markeredgewidth)
430-
if self.get_clip_on():
431-
gc.set_clip_rectangle(self.clipbox.get_bounds())
432432
funcname = self._markers.get(self._marker, '_draw_nothing')
433433
markerFunc = getattr(self, funcname)
434434
markerFunc(renderer, gc, xt, yt)

setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@
7171
matplotlib requires setuptools for installation. Please download
7272
http://peak.telecommunity.com/dist/ez_setup.py and run it (as su if
7373
you are doing a system wide install) to install the proper version of
74-
setuptools for your system""")
74+
setuptools for your system. If this is your first time upgrading
75+
matplotlib with the new setuptools requirement, you must delete the
76+
old matplotlib install directory.""")
7577

7678
import glob
7779
from distutils.core import Extension, setup
@@ -123,6 +125,7 @@
123125
raise RuntimeError("You must install one or more of numpy, Numeric, and numarray to build matplotlib")
124126

125127

128+
NUMERIX = ['numpy']
126129
rc['numerix'] = NUMERIX[-1]
127130

128131
ext_modules = []

0 commit comments

Comments
 (0)