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