8000 Micro-optimize transforms, copy array when given · matplotlib/matplotlib@b1bbb8d · GitHub
[go: up one dir, main page]

Skip to content

Commit b1bbb8d

Browse files
committed
Micro-optimize transforms, copy array when given
fix bug in backend bases, save some transformation copys
1 parent 3a2c8f3 commit b1bbb8d

File tree

3 files changed

+33
-28
lines changed

3 files changed

+33
-28
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,17 +221,18 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
221221
behavior of :meth:`draw_path_collection` can be made globally.
222222
"""
223223
path_ids = [
224-
(path, transforms.Affine2D(transform))
224+
(path, transform)
225225
for path, transform in self._iter_collection_raw_paths(
226226
master_transform, paths, all_transforms)]
227227

228228
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
229229
gc, master_transform, all_transforms, path_ids, offsets,
230230
offsetTrans, facecolors, edgecolors, linewidths, linestyles,
231231
antialiaseds, urls, offset_position):
232-
path, transform = path_id
233-
transform = transforms.Affine2D(
234-
transform.get_matrix()).translate(xo, yo)
232+
path, transform = path_id
233+
if xo != 0 or yo != 0:
234+
transform = transform.frozen()
235+
transform.translate(xo, yo)
235236
self.draw_path(gc0, path, transform, rgbFace)
236237

237238
def draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight,

lib/matplotlib/tests/test_backend_bases.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
def test_uses_per_path():
1515
id = transforms.Affine2D()
1616
paths = [path.Path.unit_regular_polygon(i) for i in range(3, 7)]
17-
tforms = [id.rotate(i) for i in range(1, 5)]
17+
tforms_matrices = [id.rotate(i).get_matrix().copy() for i in range(1, 5)]
1818
offsets = np.arange(20).reshape((10, 2))
1919
facecolors = ['red', 'green']
2020
edgecolors = ['red', 'green']
@@ -37,17 +37,17 @@ def check(master_transform, paths, all_transforms,
3737
seen = np.bincount(ids, minlength=len(raw_paths))
3838
assert set(seen).issubset([uses - 1, uses])
3939

40-
check(id, paths, tforms, offsets, facecolors, edgecolors)
41-
check(id, paths[0:1], tforms, offsets, facecolors, edgecolors)
42-
check(id, [], tforms, offsets, facecolors, edgecolors)
43-
check(id, paths, tforms[0:1], offsets, facecolors, edgecolors)
40+
check(id, paths, tforms_matrices, offsets, facecolors, edgecolors)
41+
check(id, paths[0:1], tforms_matrices, offsets, facecolors, edgecolors)
42+
check(id, [], tforms_matrices, offsets, facecolors, edgecolors)
43+
check(id, paths, tforms_matrices[0:1], offsets, facecolors, edgecolors)
4444
check(id, paths, [], offsets, facecolors, edgecolors)
4545
for n in range(0, offsets.shape[0]):
46-
check(id, paths, tforms, offsets[0:n, :], facecolors, edgecolors)
47-
check(id, paths, tforms, offsets, [], edgecolors)
48-
check(id, paths, tforms, offsets, facecolors, [])
49-
check(id, paths, tforms, offsets, [], [])
50-
check(id, paths, tforms, offsets, facecolors[0:1], edgecolors)
46+
check(id, paths, tforms_matrices, offsets[0:n, :], facecolors, edgecolors)
47+
check(id, paths, tforms_matrices, offsets, [], edgecolors)
48+
check(id, paths, tforms_matrices, offsets, facecolors, [])
49+
check(id, paths, tforms_matrices, offsets, [], [])
50+
check(id, paths, tforms_matrices, offsets, facecolors[0:1], edgecolors)
5151

5252

5353
def test_get_default_filename(tmpdir):

lib/matplotlib/transforms.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
import functools
3737
import textwrap
3838
import weakref
39-
39+
import math
4040
import numpy as np
4141
from numpy.linalg import inv
4242

@@ -1831,7 +1831,7 @@ def __init__(self, matrix=None, **kwargs):
18311831
if matrix is None:
18321832
# A bit faster than np.identity(3).
18331833
matrix = IdentityTransform._mtx.copy()
1834-
self._mtx = matrix
1834+
self._mtx = matrix.copy()
18351835
self._invalid = 0
18361836

18371837
__str__ = _make_str_method("_mtx")
@@ -1914,8 +1914,8 @@ def rotate(self, theta):
19141914
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19151915
and :meth:`scale`.
19161916
"""
1917-
a = np.cos(theta)
1918-
b = np.sin(theta)
1917+
a = math.cos(theta)
1918+
b = math.sin(theta)
19191919
rotate_mtx = np.array([[a, -b, 0.0], [b, a, 0.0], [0.0, 0.0, 1.0]],
19201920
float)
19211921
self._mtx = np.dot(rotate_mtx, self._mtx)
@@ -1930,7 +1930,7 @@ def rotate_deg(self, degrees):
19301930
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19311931
and :meth:`scale`.
19321932
"""
1933-
return self.rotate(np.deg2rad(degrees))
1933+
return self.rotate(math.radians(degrees))
19341934

19351935
def rotate_around(self, x, y, theta):
19361936
"""
@@ -1962,9 +1962,8 @@ def translate(self, tx, ty):
19621962
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19631963
and :meth:`scale`.
19641964
"""
1965-
translate_mtx = np.array(
1966-
[[1.0, 0.0, tx], [0.0, 1.0, ty], [0.0, 0.0, 1.0]], float)
1967-
self._mtx = np.dot(translate_mtx, self._mtx)
1965+
self._mtx[0, 2] += tx
1966+
self._mtx[1, 2] += ty
19681967
self.invalidate()
19691968
return self
19701969

@@ -1981,9 +1980,14 @@ def scale(self, sx, sy=None):
19811980
"""
19821981
if sy is None:
19831982
sy = sx
1984-
scale_mtx = np.array(
1985-
[[sx, 0.0, 0.0], [0.0, sy, 0.0], [0.0, 0.0, 1.0]], float)
1986-
self._mtx = np.dot(scale_mtx, self._mtx)
1983+
# explicit element-wise scaling is fastest
1984+
# the performance here.
1985+
self._mtx[0, 0] *= sx
1986+
self._mtx[0, 1] *= sx
1987+
self._mtx[0, 2] *= sx
1988+
self._mtx[1, 0] *= sy
1989+
self._mtx[1, 1] *= sy
1990+
self._mtx[1, 2] *= sy
19871991
self.invalidate()
19881992
return self
19891993

@@ -1998,8 +2002,8 @@ def skew(self, xShear, yShear):
19982002
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19992003
and :meth:`scale`.
20002004
"""
2001-
rotX = np.tan(xShear)
2002-
rotY = np.tan(yShear)
2005+
rotX = math.tan(xShear)
2006+
rotY = math.tan(yShear)
20032007
skew_mtx = np.array(
20042008
[[1.0, rotX, 0.0], [rotY, 1.0, 0.0], [0.0, 0.0, 1.0]], float)
20052009
self._mtx = np.dot(skew_mtx, self._mtx)
@@ -2017,7 +2021,7 @@ def skew_deg(self, xShear, yShear):
20172021
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
20182022
and :meth:`scale`.
20192023
"""
2020-
return self.skew(np.deg2rad(xShear), np.deg2rad(yShear))
2024+
return self.skew(math.radians(xShear), math.radians(yShear))
20212025

20222026

20232027
class IdentityTransform(Affine2DBase):

0 commit comments

Comments
 (0)
0