[Python-modules-commits] [python-mplexporter] 25/135: add path rendering

Wolfgang Borgert debacle at moszumanska.debian.org
Tue Sep 23 21:19:00 UTC 2014


This is an automated email from the git hooks/post-receive script.

debacle pushed a commit to branch master
in repository python-mplexporter.

commit 6880903d200ceaf982a43366406b070f58114654
Author: Jake Vanderplas <vanderplas at astro.washington.edu>
Date:   Thu Feb 20 13:59:11 2014 -0800

    add path rendering
---
 mplexporter/exporter.py         | 15 ++++++++-
 mplexporter/renderers/base.py   | 14 +++++++--
 mplexporter/tests/test_utils.py | 11 +++++++
 mplexporter/utils.py            | 67 ++++++++++++++++++++++++++++++++++-------
 4 files changed, 92 insertions(+), 15 deletions(-)

diff --git a/mplexporter/exporter.py b/mplexporter/exporter.py
index 4586d4b..dcb0cf5 100644
--- a/mplexporter/exporter.py
+++ b/mplexporter/exporter.py
@@ -68,7 +68,7 @@ class Exporter(object):
         if data is not None:
             return code, transform.transform(data)
         else:
-            return code            
+            return code
 
     def _crawl_fig(self, fig):
         properties = {'figwidth': fig.get_figwidth(),
@@ -92,6 +92,7 @@ class Exporter(object):
                       'dynamic': ax.get_navigate()}
         with self.renderer.draw_axes(ax, properties):
             self._extract_lines(ax)
+            self._extract_patches(ax)
             self._extract_texts(ax)
 
     def _extract_lines(self, ax):
@@ -127,3 +128,15 @@ class Exporter(object):
                                                          position)
                 style = utils.get_text_style(text)
                 self.renderer.draw_text(content, position, code, style)
+
+    def _extract_patches(self, ax):
+        for patch in ax.patches:
+            vertices, pathcodes = utils.SVG_path(patch.get_path())
+            transform = patch.get_transform()
+            coordinates, vertices = self._process_transform(transform,
+                                                            ax, vertices)
+            linestyle = utils.get_path_style(patch)
+            self.renderer.draw_path(vertices,
+                                    coordinates=coordinates,
+                                    pathcodes=pathcodes,
+                                    style=linestyle)
diff --git a/mplexporter/renderers/base.py b/mplexporter/renderers/base.py
index eef8b68..1c7d637 100644
--- a/mplexporter/renderers/base.py
+++ b/mplexporter/renderers/base.py
@@ -71,12 +71,20 @@ class Renderer(object):
     def close_axes(self, ax):
         pass
 
-    def draw_line(self, data, coordinates, style):
-        raise NotImplementedError()
-
     def draw_markers(self, data, coordinates, style):
         raise NotImplementedError()
 
     def draw_text(self, text, position, coordinates, style):
         raise NotImplementedError()
 
+    def draw_path(self, data, coordinates, pathcodes, style):
+        raise NotImplementedError()
+
+    def draw_line(self, data, coordinates, style):
+        # by default, draw the line via the draw_path() command. Some renderers
+        # might wish to override this and provide more fine-grained behavior.
+        pathcodes = ['M'] + (data.shape[0] - 1) * ['L']
+        pathstyle = dict(facecolor='none', **style)
+        pathstyle['edgecolor'] = pathstyle.pop('color')
+        pathstyle['edgewidth'] = pathstyle.pop('linewidth')
+        self.draw_path(data, coordinates, pathcodes, pathstyle)
diff --git a/mplexporter/tests/test_utils.py b/mplexporter/tests/test_utils.py
new file mode 100644
index 0000000..ac22b86
--- /dev/null
+++ b/mplexporter/tests/test_utils.py
@@ -0,0 +1,11 @@
+from numpy.testing import assert_allclose, assert_equal
+import matplotlib.pyplot as plt
+from .. import utils
+
+
+def test_path_data():
+    circle = plt.Circle((0, 0), 1)
+    vertices, codes = utils.SVG_path(circle.get_path())
+
+    assert_allclose(vertices.shape, (26, 2))
+    assert_equal(codes, ['M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'Z'])
diff --git a/mplexporter/utils.py b/mplexporter/utils.py
index f332b8f..8c6cc7a 100644
--- a/mplexporter/utils.py
+++ b/mplexporter/utils.py
@@ -2,6 +2,10 @@
 Utility Routines for Working with Matplotlib Objects
 ====================================================
 """
+import itertools
+
+import numpy as np
+
 from matplotlib.colors import colorConverter
 from matplotlib.path import Path
 from matplotlib.markers import MarkerStyle
@@ -14,7 +18,6 @@ def color_to_hex(color):
     return '#{0:02X}{1:02X}{2:02X}'.format(*(int(255 * c) for c in rgb))
 
 
-
 def many_to_one(input_dict):
     """Convert a many-to-one mapping to a one-to-one mapping"""
     return dict((key, val)
@@ -47,23 +50,64 @@ def get_dasharray(obj, i=None):
 
 PATH_DICT = {Path.LINETO: 'L',
              Path.MOVETO: 'M',
-             Path.STOP: 'STOP',
              Path.CURVE3: 'S',
              Path.CURVE4: 'C',
              Path.CLOSEPOLY: 'Z'}
 
 
-def SVG_path(path, transform=None):
-    """Return a list of SVG path tuples of a (transformed) path"""
+def SVG_path(path, transform=None, simplify=False):
+    """Construct the vertices and SVG codes for the path
+
+    Parameters
+    ----------
+    path : matplotlib.Path object
+
+    transform : matplotlib transform (optional)
+        if specified, the path will be transformed before computing the output.
+
+    Returns
+    -------
+    vertices : array
+        The shape (M, 2) array of vertices of the Path. Note that some Path
+        codes require multiple vertices, so the length of these vertices may
+        be longer than the list of path codes.
+    path_codes : list
+        A length N list of single-character path codes, N <= M. Each code is
+        a single character, in ['L','M','S','C','Z']. See the standard SVG
+        path specification for a description of these.
+    """
     if transform is not None:
         path = path.transformed(transform)
 
-    return [(PATH_DICT[path_code], vertices.tolist())
-            for vertices, path_code in path.iter_segments(simplify=False)]
-        
+    vc_tuples = [(vertices if path_code != Path.CLOSEPOLY else [],
+                  PATH_DICT[path_code])
+                 for (vertices, path_code)
+                 in path.iter_segments(simplify=simplify)]
+
+    if not vc_tuples:
+        # empty path is a special case
+        return np.zeros((0, 2)), []
+    else:
+        vertices, codes = zip(*vc_tuples)
+        vertices = np.array(list(itertools.chain(*vertices))).reshape(-1, 2)
+        return vertices, list(codes)
+
+
+def get_path_style(path):
+    """Get the style dictionary for matplotlib path objects"""
+    style = {}
+    style['alpha'] = path.get_alpha()
+    if style['alpha'] is None:
+        style['alpha'] = 1
+    style['edgecolor'] = color_to_hex(path.get_edgecolor())
+    style['facecolor'] = color_to_hex(path.get_facecolor())
+    style['edgewidth'] = path.get_linewidth()
+    style['dasharray'] = get_dasharray(path)
+    return style
+
 
 def get_line_style(line):
-    """Return the line style dict for the line"""
+    """Get the style dictionary for matplotlib line objects"""
     style = {}
     style['alpha'] = line.get_alpha()
     if style['alpha'] is None:
@@ -75,7 +119,7 @@ def get_line_style(line):
 
 
 def get_marker_style(line):
-    """Return the marker style dict for the line"""
+    """Get the style dictionary for matplotlib marker objects"""
     style = {}
     style['alpha'] = line.get_alpha()
     if style['alpha'] is None:
@@ -94,6 +138,7 @@ def get_marker_style(line):
                                    markertransform)
     return style
 
+
 def get_text_style(text):
     """Return the text style dict for a text instance"""
     style = {}
@@ -102,7 +147,7 @@ def get_text_style(text):
         style['alpha'] = 1
     style['fontsize'] = text.get_size()
     style['color'] = color_to_hex(text.get_color())
-    style['halign'] = text.get_horizontalalignment() # left, center, right
-    style['valign'] = text.get_verticalalignment() # baseline, center, top
+    style['halign'] = text.get_horizontalalignment()  # left, center, right
+    style['valign'] = text.get_verticalalignment()  # baseline, center, top
     style['rotation'] = text.get_rotation()
     return style

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-mplexporter.git



More information about the Python-modules-commits mailing list