Skip to content

Commit 62dae9d

Browse files
committed
afm an option for ps text
svn path=/trunk/matplotlib/; revision=982
1 parent 87b8098 commit 62dae9d

File tree

11 files changed

+142
-34
lines changed

11 files changed

+142
-34
lines changed

.matplotlibrc

+4
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,13 @@ savefig.dpi : 100 # figure dots per inch
171171
savefig.facecolor : white # figure facecolor when saving
172172
savefig.edgecolor : white # figure edgecolor when saving
173173

174+
# tk backend params
174175
tk.window_focus : False # Maintain shell focus for TkAgg
175176
tk.pythoninspect : False # tk sets PYTHONINSEPCT
176177

178+
# ps backend params
179+
ps.useafm : True # use of afm fonts -- breaks mathtext but results in small files
180+
177181
# Set the verbose flags. This controls how much information
178182
# matplotlib gives you at runtime and where it goes. Ther verbosity
179183
# levels are: silent, helpful, debug, debug-annoying. Any level is

CHANGELOG

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
New entries should be added at the top
22

3+
2005-02-23 Added rc param ps.useafm so backend ps can use native afm
4+
fonts or truetype. afme breaks mathtext but causes much
5+
smaller font sizes and may result in images that display
6+
better in some contexts (eg pdfs incorporated into latex
7+
docs viewed in acrobat reader). I would like to extend
8+
this approach to allow the user to use truetype only for
9+
mathtext, which should be easy.
10+
311
2005-02-23 Used sequence protocol rather than tuple in agg collection
412
drawing routines for greater flexibility - JDH
513

TODO

+4-2
Original file line numberDiff line numberDiff line change
@@ -649,8 +649,10 @@ ZeroDivisionError: SeparableTransformation::eval_scalars yin interval is zero; c
649649

650650
-- keypress mods on pan/zoom broken in QT in linux
651651

652-
-- linestyles in contour
652+
-- DONE linestyles in contour
653653

654654
-- check stabar in wx with toolbar = None or classic
655655

656-
-- nan handling?
656+
-- nan handling?
657+
658+
-- kwarg processing - eg raise on unrecognized kwargs

examples/backend_driver.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def drive(backend, python='python2.3'):
106106
#backends = ['Agg', 'Cairo', 'GDK', 'PS', 'SVG', 'Template']
107107
backends = ['Agg', 'PS', 'SVG', 'Template']
108108
#backends = [ 'GTK', 'WX', 'TkAgg']
109-
#backends = ['Agg']
109+
backends = ['PS']
110110
python = 'python2.3'
111111
for backend in backends:
112112
print 'testing %s' % backend

lib/matplotlib/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ def validate_verbose_fileo(s):
545545

546546
'tk.window_focus' : [ False, validate_bool], # Maintain shell focus for TkAgg
547547
'tk.pythoninspect' : [ False, validate_bool], # Set PYTHONINSPECT
548+
'ps.useafm' : [ False, validate_bool], # Set PYTHONINSPECT
548549
'plugins.directory' : ['.matplotlib_plugins', str], # where plugin directory is locate
549550

550551
}

lib/matplotlib/backends/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
interactive_bk = ['GTK','GTKAgg','GTKCairo','FltkAgg','QtAgg', 'TkAgg',
88
'WX','WXAgg',]
9-
non_interactive_bk = ['Agg','Cairo','GD','GDK','Paint','PS','SVG','Template']
9+
non_interactive_bk = ['Agg','Cairo','GD','GDK','Paint','PS', 'SVG','Template']
1010
all_backends = interactive_bk + non_interactive_bk
1111

1212
backend = matplotlib.get_backend()

lib/matplotlib/backends/backend_ps.py

+93-27
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
from __future__ import division
77
import sys, os, time
88
from cStringIO import StringIO
9-
from matplotlib import verbose, __version__
9+
from matplotlib import verbose, __version__, rcParams
1010
from matplotlib._pylab_helpers import Gcf
11+
from matplotlib.afm import AFM
1112
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
1213
FigureManagerBase, FigureCanvasBase
1314

@@ -34,8 +35,10 @@
3435

3536
def _num_to_str(val):
3637
if is_string_like(val): return val
38+
3739
ival = int(val)
3840
if val==ival: return str(ival)
41+
3942
s = "%1.3f"%val
4043
s = s.rstrip("0")
4144
s = s.rstrip(".")
@@ -54,6 +57,7 @@ def quote_ps_string(s):
5457

5558

5659
_fontd = {}
60+
_afmfontd = {}
5761
_type42 = []
5862

5963

@@ -130,6 +134,7 @@ def set_linedash(self, offset, seq):
130134
self.linedash = (offset,seq)
131135

132136
def set_font(self, fontname, fontsize):
137+
if rcParams['ps.useafm']: return
133138
if (fontname,fontsize) != (self.fontname,self.fontsize):
134139
out = ("/%s findfont\n"
135140
"%1.3f scalefont\n"
@@ -147,12 +152,23 @@ def get_text_width_height(self, s, prop, ismath):
147152
get the width and height in display coords of the string s
148153
with FontPropertry prop
149154
"""
155+
156+
if rcParams['ps.useafm']:
157+
if ismath: s = s[1:-1]
158+
font = self._get_font_afm(prop)
159+
l,b,w,h = font.get_str_bbox(s)
160+
161+
fontsize = prop.get_size_in_points()
162+
w *= 0.001*fontsize
163+
h *= 0.001*fontsize
164+
return w, h
165+
150166
if ismath:
151167
width, height, pswriter = math_parse_s_ps(
152168
s, 72, prop.get_size_in_points())
153169
return width, height
154170

155-
font = self._get_font(prop)
171+
font = self._get_font_ttf(prop)
156172
font.set_text(s, 0.0)
157173
w, h = font.get_width_height()
158174
w /= 64.0 # convert from subpixels
@@ -163,7 +179,15 @@ def flipy(self):
163179
'return true if small y numbers are top for renderer'
164180
return False
165181

166-
def _get_font(self, prop):
182+
def _get_font_afm(self, prop):
183+
key = hash(prop)
184+
font = _afmfontd.get(key)
185+
if font is None:
186+
font = AFM(file(fontManager.findfont(prop, fontext='afm')))
187+
_afmfontd[key] = font
188+
return font
189+
190+
def _get_font_ttf(self, prop):
167191
key = hash(prop)
168192
font = _fontd.get(key)
169193
if font is None:
@@ -381,26 +405,63 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
381405
"""
382406
# local to avoid repeated attribute lookups
383407
write = self._pswriter.write
384-
if ismath:
385-
return self.draw_mathtext(gc, x, y, s, prop, angle)
386408
if debugPS:
387409
write("% text\n")
388-
389-
font = self._get_font(prop)
390-
font.set_text(s,0)
391410

392-
self.set_color(*gc.get_rgb())
393-
self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points())
394-
write("%s m\n"%_nums_to_str(x,y))
395-
if angle:
396-
write("gsave\n")
397-
write("%s rotate\n"%_num_to_str(angle))
398-
descent = font.get_descent() / 64.0
399-
if descent:
400-
write("0 %s rmoveto\n"%_num_to_str(descent))
401-
write("(%s) show\n"%quote_ps_string(s))
402-
if angle:
403-
write("grestore\n")
411+
if rcParams['ps.useafm']:
412+
if ismath: s = s[1:-1]
413+
font = self._get_font_afm(prop)
414+
415+
l,b,w,h = font.get_str_bbox(s)
416+
417+
fontsize = prop.get_size_in_points()
418+
l *= 0.001*fontsize
419+
b *= 0.001*fontsize
420+
w *= 0.001*fontsize
421+
h *= 0.001*fontsize
422+
423+
if angle==90: l,b = -b, l # todo generalize for arb rotations
424+
425+
pos = _nums_to_str(x-l, y-b)
426+
thetext = '(%s)' % s
427+
fontname = font.get_fontname()
428+
fontsize = prop.get_size_in_points()
429+
rotate = '%1.1f rotate' % angle
430+
setcolor = '%1.3f %1.3f %1.3f setrgbcolor' % gc.get_rgb()
431+
#h = 0
432+
ps = """\
433+
gsave
434+
/%(fontname)s findfont
435+
%(fontsize)s scalefont
436+
setfont
437+
%(pos)s moveto
438+
%(rotate)s
439+
%(thetext)s
440+
%(setcolor)s
441+
show
442+
grestore
443+
""" % locals()
444+
self._draw_ps(ps, gc, None)
445+
446+
else:
447+
if ismath:
448+
return self.draw_mathtext(gc, x, y, s, prop, angle)
449+
450+
font = self._get_font_ttf(prop)
451+
font.set_text(s,0)
452+
453+
self.set_color(*gc.get_rgb())
454+
self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points())
455+
write("%s m\n"%_nums_to_str(x,y))
456+
if angle:
457+
write("gsave\n")
458+
write("%s rotate\n"%_num_to_str(angle))
459+
descent = font.get_descent() / 64.0
460+
if descent:
461+
write("0 %s rmoveto\n"%_num_to_str(descent))
462+
write("(%s) show\n"%quote_ps_string(s))
463+
if angle:
464+
write("grestore\n")
404465

405466
def new_gc(self):
406467
return GraphicsContextPS()
@@ -657,18 +718,23 @@ def print_figure(self, outfile, dpi=72,
657718
type42 = _type42 + [os.path.join(self.basepath, name) + '.ttf' \
658719
for name in bakoma_fonts]
659720
print >>fh, "%%BeginProlog"
660-
print >>fh, "/mpldict %d dict def"%(len(_psDefs)+len(type42))
721+
Ndict = len(_psDefs)
722+
if not rcParams['ps.useafm']:
723+
Ndict += len(type42)
724+
print >>fh, "/mpldict %d dict def"%Ndict
661725
print >>fh, "mpldict begin"
726+
662727
for d in _psDefs:
663728
d=d.strip()
664729
for l in d.split('\n'):
665730
print >>fh, l.strip()
666-
for font in type42:
667-
font = str(font) # TODO: handle unicode filenames
668-
print >>fh, "%%BeginFont: "+FT2Font(font).postscript_name
669-
print >>fh, encodeTTFasPS(font)
670-
print >>fh, "%%EndFont"
671-
print >>fh, "%%EndProlog"
731+
if not rcParams['ps.useafm']:
732+
for font in type42:
733+
font = str(font) # TODO: handle unicode filenames
734+
print >>fh, "%%BeginFont: "+FT2Font(font).postscript_name
735+
print >>fh, encodeTTFasPS(font)
736+
print >>fh, "%%EndFont"
737+
print >>fh, "%%EndProlog"
672738

673739
if not isEPSF: print >>fh, "%%Page: 1 1"
674740
print >>fh, "mpldict begin"

lib/matplotlib/cbook.py

+14
Original file line numberDiff line numberDiff line change
@@ -530,3 +530,17 @@ def remove(self, o):
530530
def popall(seq):
531531
'empty a list'
532532
for i in xrange(len(seq)): seq.pop()
533+
534+
def finddir(o, match, case=False):
535+
"""
536+
return all attributes of o which match string in match. if case
537+
is True require an exact case match.
538+
"""
539+
if case:
540+
names = [(name,name) for name in dir(o) if is_string_like(name)]
541+
else:
542+
names = [(name.lower(), name) for name in dir(o) if is_string_like(name)]
543+
match = match.lower()
544+
return [orig for name, orig in names if name.find(match)>=0]
545+
546+

lib/matplotlib/lines.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,10 @@ def set_data(self, *args):
188188
self._x = asarray(x, Float)
189189
self._y = asarray(y, Float)
190190

191-
if len(self._x.shape)>1: self._x = ravel(self._x)
192-
if len(self._y.shape)>1: self._y = ravel(self._y)
191+
if len(self._x.shape)>1:
192+
self._x = ravel(self._x)
193+
if len(self._y.shape)>1:
194+
self._y = ravel(self._y)
193195

194196

195197
if len(self._y)==1 and len(self._x)>1:

lib/matplotlib/pylab.py

+11
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,17 @@ def ion():
15781578
matplotlib.interactive(True)
15791579

15801580
def switch_backend(newbackend):
1581+
"""
1582+
Swtich the default backend to newbackend. This feature is
1583+
EXPERIMENTAL, and is only expected to work switching to an image
1584+
backend. Eg, if you have a bunch of PS scripts that you want to
1585+
run from an interactive ipython session, yuo may want to switch to
1586+
the PS backend before running them to avoid having a bunch of GUI
1587+
windows popup. If you try to interactively switch from one GUI
1588+
backend to another, you will explode.
1589+
1590+
Calling this command will close all open windows.
1591+
"""
15811592
close('all')
15821593
global new_figure_manager, draw_if_interactive, show
15831594
matplotlib.use(newbackend)

lib/matplotlib/text.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ def _get_layout_super(self, renderer, m):
600600
w = wb+we
601601

602602
xb, yb = self._transform.xy_tup((self._x, self._y))
603-
xe = xb+wb
603+
xe = xb+1.1*wb
604604
ye = yb+0.5*hb
605605
h = ye+he-yb
606606

0 commit comments

Comments
 (0)