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

Appearance settings

Commit b8726d0

Browse filesBrowse files
committed
Store transformations on collections as an Nx3x3 array, rather than a list of Transform objects.
When the collection has the same styling and only varies by offsets, use draw_markers instead.
1 parent d75d39f commit b8726d0
Copy full SHA for b8726d0

File tree

Expand file treeCollapse file tree

9 files changed

+5416
-5447
lines changed
Filter options
Expand file treeCollapse file tree

9 files changed

+5416
-5447
lines changed

‎lib/matplotlib/backend_bases.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_bases.py
+5-4Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
227227
path_ids = []
228228
for path, transform in self._iter_collection_raw_paths(
229229
master_transform, paths, all_transforms):
230-
path_ids.append((path, transform))
230+
path_ids.append((path, transforms.Affine2D(transform)))
231231

232232
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
233233
gc, master_transform, all_transforms, path_ids, offsets,
@@ -316,7 +316,7 @@ def _iter_collection_raw_paths(self, master_transform, paths,
316316
for i in xrange(N):
317317
path = paths[i % Npaths]
318318
if Ntransforms:
319-
transform = all_transforms[i % Ntransforms]
319+
transform = Affine2D(all_transforms[i % Ntransforms])
320320
yield path, transform + master_transform
321321

322322
def _iter_collection(self, gc, master_transform, all_transforms,
@@ -380,8 +380,9 @@ def _iter_collection(self, gc, master_transform, all_transforms,
380380
xo, yo = toffsets[i % Noffsets]
381381
if offset_position == 'data':
382382
if Ntransforms:
383-
transform = (all_transforms[i % Ntransforms] +
384-
master_transform)
383+
transform = (
384+
Affine2D(all_transforms[i % Ntransforms]) +
385+
master_transform)
385386
else:
386387
transform = master_transform
387388
xo, yo = transform.transform_point((xo, yo))

‎lib/matplotlib/collections.py

Copy file name to clipboardExpand all lines: lib/matplotlib/collections.py
+75-67Lines changed: 75 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -270,16 +270,41 @@ def draw(self, renderer):
270270
if self.get_path_effects():
271271
for pe in self.get_path_effects():
272272
pe.draw_path_collection(renderer,
273-
gc, transform.frozen(), paths, self.get_transforms(),
274-
offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
275-
self._linewidths, self._linestyles, self._antialiaseds, self._urls,
273+
gc, transform.frozen(), paths,
274+
self.get_transforms(), offsets, transOffset,
275+
self.get_facecolor(), self.get_edgecolor(),
276+
self._linewidths, self._linestyles,
277+
self._antialiaseds, self._urls,
276278
self._offset_position)
277279
else:
278-
renderer.draw_path_collection(
279-
gc, transform.frozen(), paths, self.get_transforms(),
280-
offsets, transOffset, self.get_facecolor(), self.get_edgecolor(),
281-
self._linewidths, self._linestyles, self._antialiaseds, self._urls,
282-
self._offset_position)
280+
trans = self.get_transforms()
281+
facecolors = self.get_facecolor()
282+
edgecolors = self.get_edgecolor()
283+
if (len(paths) == 1 and len(trans) <= 1 and
284+
len(facecolors) == 1 and len(edgecolors) == 1 and
285+
len(self._linewidths) == 1 and
286+
self._linestyles == [(None, None)] and
287+
len(self._antialiaseds) == 1 and len(self._urls) == 1 and
288+
self.get_hatch() is None):
289+
gc.set_foreground(tuple(edgecolors[0]))
290+
gc.set_linewidth(self._linewidths[0])
291+
gc.set_linestyle(self._linestyles[0])
292+
gc.set_antialiased(self._antialiaseds[0])
293+
gc.set_url(self._urls[0])
294+
if len(trans):
295+
transform = (transforms.Affine2D(trans[0]) +
296+
transform)
297+
renderer.draw_markers(
298+
gc, paths[0], transform.frozen(),
299+
mpath.Path(offsets), transOffset, tuple(facecolors[0]))
300+
else:
301+
renderer.draw_path_collection(
302+
gc, transform.frozen(), paths,
303+
self.get_transforms(), offsets, transOffset,
304+
self.get_facecolor(), self.get_edgecolor(),
305+
self._linewidths, self._linestyles,
306+
self._antialiaseds, self._urls,
307+
self._offset_position)
283308

284309
gc.restore()
285310
renderer.close_group(self.__class__.__name__)
@@ -686,7 +711,31 @@ def update_from(self, other):
686711
""")
687712

688713

689-
class PathCollection(Collection):
714+
class _CollectionWithSizes(Collection):
715+
"""
716+
Base class for collections that have an array of sizes.
717+
"""
718+
def get_sizes(self):
719+
return self._sizes
720+
721+
def set_sizes(self, sizes, dpi=72.0):
722+
if sizes is None:
723+
self._sizes = np.array([])
724+
self._transforms = np.empty((0, 3, 3))
725+
else:
726+
self._sizes = np.asarray(sizes)
727+
self._transforms = np.zeros((len(self._sizes), 3, 3))
728+
scale = np.sqrt(self._sizes) * dpi / 72.0
729+
self._transforms[:, 0, 0] = scale
730+
self._transforms[:, 1, 1] = scale
731+
self._transforms[:, 2, 2] = 1.0
732+
733+
def draw(self, renderer):
734+
self.set_sizes(self._sizes, self.figure.dpi)
735+
Collection.draw(self, renderer)
736+
737+
738+
class PathCollection(_CollectionWithSizes):
690739
"""
691740
This is the most basic :class:`Collection` subclass.
692741
"""
@@ -701,28 +750,16 @@ def __init__(self, paths, sizes=None, **kwargs):
701750

702751
Collection.__init__(self, **kwargs)
703752
self.set_paths(paths)
704-
self._sizes = sizes
753+
self.set_sizes(sizes)
705754

706755
def set_paths(self, paths):
707756
self._paths = paths
708757

709758
def get_paths(self):
710759
return self._paths
711760

712-
def get_sizes(self):
713-
return self._sizes
714-
715-
@allow_rasterization
716-
def draw(self, renderer):
717-
if self._sizes is not None:
718-
self._transforms = [
719-
transforms.Affine2D().scale(
720-
(np.sqrt(x) * self.figure.dpi / 72.0))
721-
for x in self._sizes]
722-
return Collection.draw(self, renderer)
723761

724-
725-
class PolyCollection(Collection):
762+
class PolyCollection(_CollectionWithSizes):
726763
@docstring.dedent_interpd
727764
def __init__(self, verts, sizes=None, closed=True, **kwargs):
728765
"""
@@ -744,7 +781,7 @@ def __init__(self, verts, sizes=None, closed=True, **kwargs):
744781
%(Collection)s
745782
"""
746783
Collection.__init__(self, **kwargs)
747-
self._sizes = sizes
784+
self.set_sizes(sizes)
748785
self.set_verts(verts, closed)
749786

750787
def set_verts(self, verts, closed=True):
@@ -773,15 +810,6 @@ def set_verts(self, verts, closed=True):
773810

774811
set_paths = set_verts
775812

776-
@allow_rasterization
777-
def draw(self, renderer):
778-
if self._sizes is not None:
779-
self._transforms = [
780-
transforms.Affine2D().scale(
781-
(np.sqrt(x) * self.figure.dpi / 72.0))
782-
for x in self._sizes]
783-
return Collection.draw(self, renderer)
784-
785813

786814
class BrokenBarHCollection(PolyCollection):
787815
"""
@@ -830,7 +858,7 @@ def span_where(x, ymin, ymax, where, **kwargs):
830858
return collection
831859

832860

833-
class RegularPolyCollection(Collection):
861+
class RegularPolyCollection(_CollectionWithSizes):
834862
"""Draw a collection of regular polygons with *numsides*."""
835863
_path_generator = mpath.Path.unit_regular_polygon
836864

@@ -871,29 +899,18 @@ def __init__(self,
871899
)
872900
"""
873901
Collection.__init__(self, **kwargs)
874-
self._sizes = sizes
902+
self.set_sizes(sizes)
875903
self._numsides = numsides
876904
self._paths = [self._path_generator(numsides)]
877905
self._rotation = rotation
878906
self.set_transform(transforms.IdentityTransform())
879907

880-
@allow_rasterization
881-
def draw(self, renderer):
882-
self._transforms = [
883-
transforms.Affine2D().rotate(-self._rotation).scale(
884-
(np.sqrt(x) * self.figure.dpi / 72.0) / np.sqrt(np.pi))
885-
for x in self._sizes]
886-
return Collection.draw(self, renderer)
887-
888908
def get_numsides(self):
889909
return self._numsides
890910

891911
def get_rotation(self):
892912
return self._rotation
893913

894-
def get_sizes(self):
895-
return self._sizes
896-
897914

898915
class StarPolygonCollection(RegularPolyCollection):
899916
"""
@@ -1339,7 +1356,7 @@ def get_color(self):
13391356
return self.get_colors()[0]
13401357

13411358

1342-
class CircleCollection(Collection):
1359+
class CircleCollection(_CollectionWithSizes):
13431360
"""
13441361
A collection of circles, drawn using splines.
13451362
"""
@@ -1352,24 +1369,10 @@ def __init__(self, sizes, **kwargs):
13521369
%(Collection)s
13531370
"""
13541371
Collection.__init__(self, **kwargs)
1355-
self._sizes = sizes
1372+
self.set_sizes(sizes)
13561373
self.set_transform(transforms.IdentityTransform())
13571374
self._paths = [mpath.Path.unit_circle()]
13581375

1359-
def get_sizes(self):
1360-
"return sizes of circles"
1361-
return self._sizes
1362-
1363-
@allow_rasterization
1364-
def draw(self, renderer):
1365-
# sizes is the area of the circle circumscribing the polygon
1366-
# in points^2
1367-
self._transforms = [
1368-
transforms.Affine2D().scale(
1369-
(np.sqrt(x) * self.figure.dpi / 72.0) / np.sqrt(np.pi))
1370-
for x in self._sizes]
1371-
return Collection.draw(self, renderer)
1372-
13731376

13741377
class EllipseCollection(Collection):
13751378
"""
@@ -1416,7 +1419,6 @@ def _set_transforms(self):
14161419
"""
14171420
Calculate transforms immediately before drawing.
14181421
"""
1419-
self._transforms = []
14201422
ax = self.axes
14211423
fig = self.figure
14221424

@@ -1439,10 +1441,16 @@ def _set_transforms(self):
14391441
else:
14401442
raise ValueError('unrecognized units: %s' % self._units)
14411443

1442-
_affine = transforms.Affine2D
1443-
for x, y, a in zip(self._widths, self._heights, self._angles):
1444-
trans = _affine().scale(x * sc, y * sc).rotate(a)
1445-
self._transforms.append(trans)
1444+
self._transforms = np.zeros((len(self._widths), 3, 3))
1445+
widths = self._widths * sc
1446+
heights = self._heights * sc
1447+
sin_angle = np.cos(np.deg2rad(self._angles))
1448+
cos_angle = np.cos(np.deg2rad(self._angles))
1449+
self._transforms[:, 0, 0] = widths * cos_angle
1450+
self._transforms[:, 0, 1] = heights * -sin_angle
1451+
self._transforms[:, 1, 0] = widths * sin_angle
1452+
self._transforms[:, 1, 1] = heights * cos_angle
1453+
self._transforms[:, 2, 2] = 1.0
14461454

14471455
if self._units == 'xy':
14481456
m = ax.transData.get_affine().get_matrix().copy()

‎lib/matplotlib/image.py

Copy file name to clipboardExpand all lines: lib/matplotlib/image.py
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,8 @@ def pil_to_array(pilImage):
13131313
is MxNx3. For RGBA images the return value is MxNx4
13141314
"""
13151315
def toarray(im, dtype=np.uint8):
1316-
"""Teturn a 1D array of dtype."""
1316+
"""Return a 1D array of dtype."""
1317+
# Pillow wants us to use "tobytes"
13171318
if hasattr(im, 'tobytes'):
13181319
x_str = im.tobytes('raw', im.mode)
13191320
else:
Binary file not shown.
Loading

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.