From 8b65fa1c9107f2a44f7f8d445ac6318c8989e4eb Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sat, 22 Dec 2018 17:21:08 +0100 Subject: [PATCH 1/2] Speed up Path.iter_segments() Using the Gtk3Cairo backend with wire3d_animation_sgskip.py: Before: 9.16 fps After: 9.95 fps The main speedup is from iterating and keeping the common non-curve case simple. --- lib/matplotlib/path.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index 4c9a3f69c324..d37803a106e9 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -399,24 +399,22 @@ def iter_segments(self, transform=None, remove_nans=True, clip=None, snap=snap, stroke_width=stroke_width, simplify=simplify, curves=curves, sketch=sketch) - vertices = cleaned.vertices - codes = cleaned.codes - len_vertices = vertices.shape[0] # Cache these object lookups for performance in the loop. NUM_VERTICES_FOR_CODE = self.NUM_VERTICES_FOR_CODE STOP = self.STOP - i = 0 - while i < len_vertices: - code = codes[i] + vertices = iter(cleaned.vertices) + codes = iter(cleaned.codes) + for curr_vertices, code in zip(vertices, codes): if code == STOP: - return - else: - num_vertices = NUM_VERTICES_FOR_CODE[code] - curr_vertices = vertices[i:i+num_vertices].flatten() - yield curr_vertices, code - i += num_vertices + break + extra_vertices = NUM_VERTICES_FOR_CODE[code] - 1 + if extra_vertices: + for i in range(extra_vertices): + next(codes) + curr_vertices = np.append(curr_vertices, next(vertices)) + yield curr_vertices, code def cleaned(self, transform=None, remove_nans=False, clip=None, quantize=False, simplify=False, curves=False, From 3b8689afe34663e3c277d8bd897d1fad0ce10f8f Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Sun, 23 Dec 2018 18:46:11 +0100 Subject: [PATCH 2/2] Path: change the type of the code type constants to match the type of the codes array The matching types make comparisons between the constants and values of the codes array faster. Using the Gtk3Cairo backend with wire3d_animation_sgskip.py: Before: 9.95 fps After: 15.26 fps The main areas where this helps for the cairo case is the faster comparisons in Path.iter_segments() and in _append_paths() of the cairo backend. --- .../2018-12-23-path-code-types.rst | 7 +++++++ lib/matplotlib/path.py | 16 ++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 doc/api/next_api_changes/2018-12-23-path-code-types.rst diff --git a/doc/api/next_api_changes/2018-12-23-path-code-types.rst b/doc/api/next_api_changes/2018-12-23-path-code-types.rst new file mode 100644 index 000000000000..e8e3177ef85e --- /dev/null +++ b/doc/api/next_api_changes/2018-12-23-path-code-types.rst @@ -0,0 +1,7 @@ +Path code types like ``Path.MOVETO`` are now ``np.uint8`` instead of ``int`` +```````````````````````````````````````````````````````````````````````````` + +``Path.STOP``, ``Path.MOVETO``, ``Path.LINETO``, ``Path.CURVE3``, +``Path.CURVE4`` and ``Path.CLOSEPOLY`` are now of the type ``Path.code_type`` +(``np.uint8`` by default) instead of plain ``int``. This makes their type +match the array value type of the ``Path.codes`` array. diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index d37803a106e9..24dee6e58071 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -74,13 +74,15 @@ class Path(object): """ + code_type = np.uint8 + # Path codes - STOP = 0 # 1 vertex - MOVETO = 1 # 1 vertex - LINETO = 2 # 1 vertex - CURVE3 = 3 # 2 vertices - CURVE4 = 4 # 3 vertices - CLOSEPOLY = 79 # 1 vertex + STOP = code_type(0) # 1 vertex + MOVETO = code_type(1) # 1 vertex + LINETO = code_type(2) # 1 vertex + CURVE3 = code_type(3) # 2 vertices + CURVE4 = code_type(4) # 3 vertices + CLOSEPOLY = code_type(79) # 1 vertex #: A dictionary mapping Path codes to the number of vertices that the #: code expects. @@ -91,8 +93,6 @@ class Path(object): CURVE4: 3, CLOSEPOLY: 1} - code_type = np.uint8 - def __init__(self, vertices, codes=None, _interpolation_steps=1, closed=False, readonly=False): """