8000 Micro-optimize transforms, copy given array upon transform initializa… · matplotlib/matplotlib@88e40cb · GitHub
[go: up one dir, main page]

Skip to content

Commit 88e40cb

Browse files
committed
Micro-optimize transforms, copy given array upon transform initialization.
Fix revealed bug in backend bases, save some transformation copys
1 parent 005c7a6 commit 88e40cb

File tree

3 files changed

+36
-32
lines changed

3 files changed

+36
-32
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 8 additions & 9 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343

4444
import matplotlib as mpl
4545
from matplotlib import (
46-
backend_tools as tools, cbook, colors, textpath, tight_bbox, transforms,
47-
widgets, get_backend, is_interactive, rcParams)
46+
backend_tools as tools, cbook, colors, textpath, tight_bbox,
47+
transforms, widgets, get_backend, is_interactive, rcParams)
4848
from matplotlib._pylab_helpers import Gcf
4949
from matplotlib.backend_managers import ToolManager
5050
from matplotlib.transforms import Affine2D
@@ -220,18 +220,17 @@ def draw_path_collection(self, gc, master_transform, paths, all_transforms,
220220
recommended to use those generators, so that changes to the
221221
behavior of :meth:`draw_path_collection` can be made globally.
222222
"""
223-
path_ids = [
224-
(path, transforms.Affine2D(transform))
225-
for path, transform in self._iter_collection_raw_paths(
226-
master_transform, paths, all_transforms)]
223+
path_ids = self._iter_collection_raw_paths(master_transform,
224+
paths, all_transforms)
227225

228226
for xo, yo, path_id, gc0, rgbFace in self._iter_collection(
229-
gc, master_transform, all_transforms, path_ids, offsets,
227+
gc, master_transform, all_transforms, list(path_ids), offsets,
230228
offsetTrans, facecolors, edgecolors, linewidths, linestyles,
231229
antialiaseds, urls, offset_position):
232230
path, transform = path_id
233-
transform = transforms.Affine2D(
234-
transform.get_matrix()).translate(xo, yo)
231+
if xo != 0 or yo != 0:
232+
transform = transform.frozen()
233+
transform.translate(xo, yo)
235234
self.draw_path(gc0, path, transform, rgbFace)
236235

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

lib/matplotlib/tests/test_backend_bases.py

Lines changed: 11 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,18 @@ 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, :],
47+
facecolors, edgecolors)
48+
check(id, paths, tforms_matrices, offsets, [], edgecolors)
49+
check(id, paths, tforms_matrices, offsets, facecolors, [])
50+
check(id, paths, tforms_matrices, offsets, [], [])
51+
check(id, paths, tforms_matrices, offsets, facecolors[0:1], edgecolors)
5152

5253

5354
def test_get_default_filename(tmpdir):

lib/matplotlib/transforms.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import functools
3737
import textwrap
3838
import weakref
39+
import math
3940

4041
import numpy as np
4142
from numpy.linalg import inv
@@ -1831,7 +1832,7 @@ def __init__(self, matrix=None, **kwargs):
18311832
if matrix is None:
18321833
# A bit faster than np.identity(3).
18331834
matrix = IdentityTransform._mtx.copy()
1834-
self._mtx = matrix
1835+
self._mtx = matrix.copy()
18351836
self._invalid = 0
18361837

18371838
__str__ = _make_str_method("_mtx")
@@ -1914,8 +1915,8 @@ def rotate(self, theta):
19141915
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19151916
and :meth:`scale`.
19161917
"""
1917-
a = np.cos(theta)
1918-
b = np.sin(theta)
1918+
a = math.cos(theta)
1919+
b = math.sin(theta)
19191920
rotate_mtx = np.array([[a, -b, 0.0], [b, a, 0.0], [0.0, 0.0, 1.0]],
19201921
float)
19211922
self._mtx = np.dot(rotate_mtx, self._mtx)
@@ -1930,7 +1931,7 @@ def rotate_deg(self, degrees):
19301931
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19311932
and :meth:`scale`.
19321933
"""
1933-
return self.rotate(np.deg2rad(degrees))
1934+
return self.rotate(math.radians(degrees))
19341935

19351936
def rotate_around(self, x, y, theta):
19361937
"""
@@ -1962,9 +1963,8 @@ def translate(self, tx, ty):
19621963
calls to :meth:`rotate`, :meth:`rotate_deg`, :meth:`translate`
19631964
and :meth:`scale`.
19641965
"""
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)
1966+
self._mtx[0, 2] += tx
1967+
self._mtx[1, 2] += ty
19681968
self.invalidate()
19691969
return self
19701970

@@ -1981,9 +1981,13 @@ def scale(self, sx, sy=None):
19811981
"""
19821982
if sy is None:
19831983
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)
1984+
# explicit element-wise scaling is fastest
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