Skip to content

Commit c883c00

Browse files
committed
initial implementation of patheffect for collections
1 parent 5bda706 commit c883c00

File tree

3 files changed

+85
-20
lines changed

3 files changed

+85
-20
lines changed

examples/pylab_examples/patheffect_demo.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
arr = np.arange(25).reshape((5,5))
2929
ax2.imshow(arr)
3030
cntr = ax2.contour(arr, colors="k")
31+
32+
plt.setp(cntr.collections,
33+
path_effects=[PathEffects.withStroke(linewidth=3,
34+
foreground="w")])
35+
36+
3137
clbls = ax2.clabel(cntr, fmt="%2.0f", use_clabeltext=True)
3238
plt.setp(clbls,
3339
path_effects=[PathEffects.withStroke(linewidth=3,

lib/matplotlib/collections.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ def __init__(self,
9191
urls=None,
9292
offset_position='screen',
9393
zorder=1,
94+
path_effects=None,
9495
**kwargs
9596
):
9697
"""
@@ -123,6 +124,7 @@ def __init__(self,
123124
else:
124125
self._uniform_offsets = offsets
125126

127+
self._path_effects = None
126128
self.update(kwargs)
127129
self._paths = None
128130

@@ -255,11 +257,21 @@ def draw(self, renderer):
255257
if self._hatch:
256258
gc.set_hatch(self._hatch)
257259

258-
renderer.draw_path_collection(
259-
gc, transform.frozen(), paths, self.get_transforms(),
260-
offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
261-
self._linewidths, self._linestyles, self._antialiaseds, self._urls,
262-
self._offset_position)
260+
if self.get_path_effects():
261+
#from patheffects import PathEffectsRenderer
262+
for pe in self.get_path_effects():
263+
pe.draw_path_collection(renderer,
264+
gc, transform.frozen(), paths, self.get_transforms(),
265+
offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
266+
self._linewidths, self._linestyles, self._antialiaseds, self._urls,
267+
self._offset_position)
268+
else:
269+
270+
renderer.draw_path_collection(
271+
gc, transform.frozen(), paths, self.get_transforms(),
272+
offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
273+
self._linewidths, self._linestyles, self._antialiaseds, self._urls,
274+
self._offset_position)
263275

264276
gc.restore()
265277
renderer.close_group(self.__class__.__name__)
@@ -638,6 +650,17 @@ def update_from(self, other):
638650
self.cmap = other.cmap
639651
# self.update_dict = other.update_dict # do we need to copy this? -JJL
640652

653+
def set_path_effects(self, path_effects):
654+
"""
655+
set path_effects, which should be a list of instances of
656+
matplotlib.patheffect._Base class or its derivatives.
657+
"""
658+
self._path_effects = path_effects
659+
660+
def get_path_effects(self):
661+
return self._path_effects
662+
663+
641664
# these are not available for the object inspector until after the
642665
# class is built so we define an initial set here for the init
643666
# function and they will be overridden after object defn

lib/matplotlib/patheffects.py

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,46 @@ def draw_path(self, renderer, gc, tpath, affine, rgbFace):
5353
"""
5454
renderer.draw_path(gc, tpath, affine, rgbFace)
5555

56+
def draw_path_collection(self, renderer,
57+
gc, master_transform, paths, all_transforms,
58+
offsets, offsetTrans, facecolors, edgecolors,
59+
linewidths, linestyles, antialiaseds, urls,
60+
offset_position):
61+
"""
62+
Draws a collection of paths selecting drawing properties from
63+
the lists *facecolors*, *edgecolors*, *linewidths*,
64+
*linestyles* and *antialiaseds*. *offsets* is a list of
65+
offsets to apply to each of the paths. The offsets in
66+
*offsets* are first transformed by *offsetTrans* before being
67+
applied. *offset_position* may be either "screen" or "data"
68+
depending on the space that the offsets are in.
69+
70+
This provides a fallback implementation of
71+
:meth:`draw_path_collection` that makes multiple calls to
72+
:meth:`draw_path`. Some backends may want to override this in
73+
order to render each set of path data only once, and then
74+
reference that path multiple times with the different offsets,
75+
colors, styles etc. The generator methods
76+
:meth:`_iter_collection_raw_paths` and
77+
:meth:`_iter_collection` are provided to help with (and
78+
standardize) the implementation across backends. It is highly
79+
recommended to use those generators, so that changes to the
80+
behavior of :meth:`draw_path_collection` can be made globally.
81+
"""
82+
path_ids = []
83+
for path, transform in renderer._iter_collection_raw_paths(
84+
master_transform, paths, all_transforms):
85+
path_ids.append((path, transform))
86+
87+
for xo, yo, path_id, gc0, rgbFace in renderer._iter_collection(
88+
gc, master_transform, all_transforms, path_ids, offsets,
89+
offsetTrans, facecolors, edgecolors, linewidths, linestyles,
90+
antialiaseds, urls, offset_position):
91+
path, transform = path_id
92+
transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo)
93+
self.draw_path(renderer, gc0, path, transform, rgbFace)
94+
95+
5696
def draw_tex(self, renderer, gc, x, y, s, prop, angle, ismath='TeX!'):
5797
self._draw_text_as_path(renderer, gc, x, y, s, prop, angle, ismath="TeX")
5898

@@ -101,21 +141,6 @@ def draw_markers(self, renderer, gc, marker_path, marker_trans, path, trans, rgb
101141
marker_trans + transforms.Affine2D().translate(x, y),
102142
rgbFace)
103143

104-
# def draw_path_collection(self, renderer,
105-
# gc, master_transform, paths, all_transforms,
106-
# offsets, offsetTrans, facecolors, edgecolors,
107-
# linewidths, linestyles, antialiaseds, urls):
108-
# path_ids = []
109-
# for path, transform in renderer._iter_collection_raw_paths(
110-
# master_transform, paths, all_transforms):
111-
# path_ids.append((path, transform))
112-
113-
# for xo, yo, path_id, gc0, rgbFace in renderer._iter_collection(
114-
# gc, path_ids, offsets, offsetTrans, facecolors, edgecolors,
115-
# linewidths, linestyles, antialiaseds, urls):
116-
# path, transform = path_id
117-
# transform = transforms.Affine2D(transform.get_matrix()).translate(xo, yo)
118-
# self.draw_path(renderer, gc0, path, transform, rgbFace)
119144

120145
class ProxyRenderer(object):
121146
def __init__(self, path_effect, renderer):
@@ -138,6 +163,17 @@ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None)
138163
gc, marker_path, marker_trans, path, trans,
139164
rgbFace=rgbFace)
140165

166+
def draw_path_collection(self, gc, master_transform, paths, all_transforms,
167+
offsets, offsetTrans, facecolors, edgecolors,
168+
linewidths, linestyles, antialiaseds, urls,
169+
offset_position):
170+
pe = self._path_effect
171+
pe.draw_path_collection(self._renderer,
172+
gc, master_transform, paths, all_transforms,
173+
offsets, offsetTrans, facecolors, edgecolors,
174+
linewidths, linestyles, antialiaseds, urls,
175+
offset_position)
176+
141177

142178
class Normal(_Base):
143179
"""

0 commit comments

Comments
 (0)