Revision: 7606
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7606&view=rev
Author:   leejjoon
Date:     2009-08-30 20:26:05 +0000 (Sun, 30 Aug 2009)

Log Message:
-----------
add TextPath class in text.py. Update demo_text_path.py

Modified Paths:
--------------
    trunk/matplotlib/examples/pylab_examples/demo_text_path.py
    trunk/matplotlib/lib/matplotlib/text.py

Modified: trunk/matplotlib/examples/pylab_examples/demo_text_path.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/demo_text_path.py  2009-08-30 
18:30:29 UTC (rev 7605)
+++ trunk/matplotlib/examples/pylab_examples/demo_text_path.py  2009-08-30 
20:26:05 UTC (rev 7606)
@@ -4,147 +4,54 @@
 import matplotlib.pyplot as plt
 from matplotlib.image import BboxImage
 import numpy as np
-from matplotlib.transforms import Affine2D, IdentityTransform
+from matplotlib.transforms import IdentityTransform
 
-import matplotlib.font_manager as font_manager
-from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING
-from matplotlib.font_manager import FontProperties
-from matplotlib.path import Path
 import matplotlib.patches as mpatches
 
 from matplotlib.offsetbox import AnnotationBbox,\
      AnchoredOffsetbox, AuxTransformBox
 
-#from matplotlib.offsetbox import
-
 from matplotlib.cbook import get_sample_data
 
+from matplotlib.text import TextPath
 
-class TextPatch(mpatches.PathPatch):
 
-    FONT_SCALE = 100.
+class PathClippedImagePatch(mpatches.PathPatch):
+    """
+    The given image is used to draw the face of the patch. Internally,
+    it uses BboxImage whose clippath set to the path of the patch.
 
-    def __init__(self, xy, s, size=None, prop=None, bbox_image=None,
-                 *kl, **kwargs):
-        if prop is None:
-            prop = FontProperties()
-
-        if size is None:
-            size = prop.get_size_in_points()
-
-        self._xy = xy
-        self.set_size(size)
-
-        self.text_path = self.text_get_path(prop, s)
-
-        mpatches.PathPatch.__init__(self, self.text_path, *kl, **kwargs)
-
+    FIXME : The result is currently dpi dependent.
+    """
+    def __init__(self, path, bbox_image, **kwargs):
+        mpatches.PathPatch.__init__(self, path, **kwargs)
+        self._facecolor = "none"
         self._init_bbox_image(bbox_image)
 
-
+    def set_facecolor(self, color):
+        pass
+    
     def _init_bbox_image(self, im):
 
-        if im is None:
-            self.bbox_image = None
-        else:
-            bbox_image = BboxImage(self.get_window_extent,
-                                   norm = None,
-                                   origin=None,
-                                   )
-            bbox_image.set_transform(IdentityTransform())
+        bbox_image = BboxImage(self.get_window_extent,
+                               norm = None,
+                               origin=None,
+                               )
+        bbox_image.set_transform(IdentityTransform())
 
-            bbox_image.set_data(im)
-            self.bbox_image = bbox_image
+        bbox_image.set_data(im)
+        self.bbox_image = bbox_image
 
     def draw(self, renderer=None):
 
 
-        if self.bbox_image is not None:
-            # the clip path must be updated every draw. any solution? -JJ
-            self.bbox_image.set_clip_path(self.text_path, self.get_transform())
-            self.bbox_image.draw(renderer)
+        # the clip path must be updated every draw. any solution? -JJ
+        self.bbox_image.set_clip_path(self._path, self.get_transform())
+        self.bbox_image.draw(renderer)
 
         mpatches.PathPatch.draw(self, renderer)
 
 
-    def set_size(self, size):
-        self._size = size
-
-    def get_size(self):
-        return self._size
-
-    def get_patch_transform(self):
-        tr = Affine2D().scale(self._size/self.FONT_SCALE, 
self._size/self.FONT_SCALE)
-        return tr.translate(*self._xy)
-
-    def glyph_char_path(self, glyph, currx=0.):
-
-        verts, codes = [], []
-        for step in glyph.path:
-            if step[0] == 0:   # MOVE_TO
-                verts.append((step[1], step[2]))
-                codes.append(Path.MOVETO)
-            elif step[0] == 1: # LINE_TO
-                verts.append((step[1], step[2]))
-                codes.append(Path.LINETO)
-            elif step[0] == 2: # CURVE3
-                verts.extend([(step[1], step[2]),
-                               (step[3], step[4])])
-                codes.extend([Path.CURVE3, Path.CURVE3])
-            elif step[0] == 3: # CURVE4
-                verts.extend([(step[1], step[2]),
-                              (step[3], step[4]),
-                              (step[5], step[6])])
-                codes.extend([Path.CURVE4, Path.CURVE4, Path.CURVE4])
-            elif step[0] == 4: # ENDPOLY
-                verts.append((0, 0,))
-                codes.append(Path.CLOSEPOLY)
-
-        verts = [(x+currx, y) for (x,y) in verts]
-
-        return verts, codes
-
-
-    def text_get_path(self, prop, s):
-
-        fname = font_manager.findfont(prop)
-        font = FT2Font(str(fname))
-
-        font.set_size(self.FONT_SCALE, 72)
-
-        cmap = font.get_charmap()
-        lastgind = None
-
-        currx = 0
-
-        verts, codes = [], []
-
-        for c in s:
-
-            ccode = ord(c)
-            gind = cmap.get(ccode)
-            if gind is None:
-                ccode = ord('?')
-                gind = 0
-            glyph = font.load_char(ccode, flags=LOAD_NO_HINTING)
-
-
-            if lastgind is not None:
-                kern = font.get_kerning(lastgind, gind, KERNING_DEFAULT)
-            else:
-                kern = 0
-            currx += (kern / 64.0) #/ (self.FONT_SCALE)
-
-            verts1, codes1 = self.glyph_char_path(glyph, currx)
-            verts.extend(verts1)
-            codes.extend(codes1)
-
-
-            currx += (glyph.linearHoriAdvance / 65536.0) #/ (self.FONT_SCALE)
-            lastgind = gind
-
-        return Path(verts, codes)
-
 if 1:
 
     fig = plt.figure(1)
@@ -156,11 +63,13 @@
     from matplotlib._png import read_png
     fn = get_sample_data("lena.png", asfileobj=False)
     arr = read_png(fn)
-    p = TextPatch((0, 0), "!?", size=150, fc="none", ec="k",
-                  bbox_image=arr,
-                  transform=IdentityTransform())
-    p.set_clip_on(False)
 
+    text_path = TextPath((0, 0), "!?", size=150)
+    p = PathClippedImagePatch(text_path, arr, ec="k",
+                              transform=IdentityTransform())
+
+    #p.set_clip_on(False)
+
     # make offset box
     offsetbox = AuxTransformBox(IdentityTransform())
     offsetbox.add_artist(p)
@@ -176,21 +85,21 @@
 
     ax = plt.subplot(212)
 
-    shadow1 = TextPatch((3, -2), "TextPath", size=70, fc="none", ec="0.6", 
lw=3,
-                   transform=IdentityTransform())
-    shadow2 = TextPatch((3, -2), "TextPath", size=70, fc="0.3", ec="none",
-                   transform=IdentityTransform())
-
     arr = np.arange(256).reshape(1,256)/256.
-    text_path = TextPatch((0, 0), "TextPath", size=70, fc="none", ec="none", 
lw=1,
-                          bbox_image=arr,
-                          transform=IdentityTransform())
 
+    text_path = TextPath((0, 0), "TextPath", size=70)
+    text_patch = PathClippedImagePatch(text_path, arr, ec="none",
+                                       transform=IdentityTransform())
+
+    shadow1 = mpatches.Shadow(text_patch, 3, -2, props=dict(fc="none", 
ec="0.6", lw=3))
+    shadow2 = mpatches.Shadow(text_patch, 3, -2, props=dict(fc="0.3", 
ec="none"))
+
+
     # make offset box
     offsetbox = AuxTransformBox(IdentityTransform())
     offsetbox.add_artist(shadow1)
     offsetbox.add_artist(shadow2)
-    offsetbox.add_artist(text_path)
+    offsetbox.add_artist(text_patch)
 
     # place the anchored offset box using AnnotationBbox
     ab = AnnotationBbox(offsetbox, (0.5, 0.5),
@@ -198,16 +107,13 @@
                         boxcoords="offset points",
                         box_alignment=(0.5,0.5),
                         )
+    #text_path.set_size(10)
 
-
     ax.add_artist(ab)
 
     ax.set_xlim(0, 1)
     ax.set_ylim(0, 1)
 
 
-
-
-
     plt.draw()
     plt.show()

Modified: trunk/matplotlib/lib/matplotlib/text.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/text.py     2009-08-30 18:30:29 UTC (rev 
7605)
+++ trunk/matplotlib/lib/matplotlib/text.py     2009-08-30 20:26:05 UTC (rev 
7606)
@@ -23,6 +23,11 @@
 
 import matplotlib.nxutils as nxutils
 
+from matplotlib.path import Path
+import matplotlib.font_manager as font_manager
+from matplotlib.ft2font import FT2Font, KERNING_DEFAULT, LOAD_NO_HINTING
+
+
 def _process_text_args(override, fontdict=None, **kwargs):
     "Return an override dict.  See :func:`~pyplot.text' docstring for info"
 
@@ -1764,3 +1769,174 @@
 
 docstring.interpd.update(Annotation=Annotation.__init__.__doc__)
 
+
+class TextPath(Path):
+    """
+    Create a path from the text.
+    """
+
+    # TODO : math text is currently not supported, but it would not be easy.
+
+    FONT_SCALE = 100.
+
+    def __init__(self, xy, s, size=None, prop=None,
+                 _interpolation_steps=1,
+                 *kl, **kwargs):
+        """
+        Create a path from the text. No support for TeX yet. Note that
+        it simply is a path, not an artist. You need to use the
+        PathPatch (or other artists) to draw this path onto the
+        canvas.
+        
+        xy : position of the text.
+        s : text
+        size : font size
+        prop : font property
+        """
+
+
+        if prop is None:
+            prop = FontProperties()
+
+        if size is None:
+            size = prop.get_size_in_points()
+
+
+        self._xy = xy
+        self.set_size(size)
+
+        self._cached_vertices = None
+
+        self._vertices, self._codes = self.text_get_vertices_codes(prop, s)
+
+        self.should_simplify = False
+        self.simplify_threshold = rcParams['path.simplify_threshold']
+        self.has_nonfinite = False
+        self._interpolation_steps = _interpolation_steps
+
+
+    def set_size(self, size):
+        """
+        set the size of the text
+        """
+        self._size = size
+        self._invalid = True
+
+    def get_size(self):
+        """
+        get the size of the text
+        """
+        return self._size
+
+    def _get_vertices(self):
+        """
+        Return the cached path after updating it if necessary.
+        """
+        self._revalidate_path()
+        return self._cached_vertices
+
+    def _get_codes(self):
+        """
+        Return the codes
+        """
+        return self._codes
+    
+    vertices = property(_get_vertices)
+    codes = property(_get_codes)
+
+    def _revalidate_path(self):
+        """
+        update the path if necessary.
+
+        The path for the text is initially create with the font size
+        of FONT_SCALE, and this path is rescaled to other size when
+        necessary.
+
+        """
+        if self._invalid or \
+               (self._cached_vertices is None):
+            tr = Affine2D().scale(self._size/self.FONT_SCALE,
+                                  
self._size/self.FONT_SCALE).translate(*self._xy)
+            self._cached_vertices = tr.transform(self._vertices)
+            self._invalid = False
+
+
+    def glyph_char_path(self, glyph, currx=0.):
+        """
+        convert the glyph to vertices and codes. Mostly copied from
+        backend_svg.py.
+        """
+        verts, codes = [], []
+        for step in glyph.path:
+            if step[0] == 0:   # MOVE_TO
+                verts.append((step[1], step[2]))
+                codes.append(Path.MOVETO)
+            elif step[0] == 1: # LINE_TO
+                verts.append((step[1], step[2]))
+                codes.append(Path.LINETO)
+            elif step[0] == 2: # CURVE3
+                verts.extend([(step[1], step[2]),
+                               (step[3], step[4])])
+                codes.extend([Path.CURVE3, Path.CURVE3])
+            elif step[0] == 3: # CURVE4
+                verts.extend([(step[1], step[2]),
+                              (step[3], step[4]),
+                              (step[5], step[6])])
+                codes.extend([Path.CURVE4, Path.CURVE4, Path.CURVE4])
+            elif step[0] == 4: # ENDPOLY
+                verts.append((0, 0,))
+                codes.append(Path.CLOSEPOLY)
+
+        verts = [(x+currx, y) for (x,y) in verts]
+
+        return verts, codes
+
+
+    def text_get_vertices_codes(self, prop, s):
+        """
+        convert the string *s* to vertices and codes using the
+        provided font property *prop*. Mostly copied from
+        backend_svg.py.
+        """
+
+        fname = font_manager.findfont(prop)
+        font = FT2Font(str(fname))
+
+        font.set_size(self.FONT_SCALE, 72)
+
+        cmap = font.get_charmap()
+        lastgind = None
+
+        currx = 0
+
+        verts, codes = [], []
+
+
+        # I'm not sure if I get kernings right. Needs to be verified. -JJL
+
+        for c in s:
+
+            ccode = ord(c)
+            gind = cmap.get(ccode)
+            if gind is None:
+                ccode = ord('?')
+                gind = 0
+            glyph = font.load_char(ccode, flags=LOAD_NO_HINTING)
+
+
+            if lastgind is not None:
+                kern = font.get_kerning(lastgind, gind, KERNING_DEFAULT)
+            else:
+                kern = 0
+            currx += (kern / 64.0) #/ (self.FONT_SCALE)
+
+            verts1, codes1 = self.glyph_char_path(glyph, currx)
+            verts.extend(verts1)
+            codes.extend(codes1)
+
+
+            currx += (glyph.linearHoriAdvance / 65536.0) #/ (self.FONT_SCALE)
+            lastgind = gind
+
+        return verts, codes
+


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to