Skip to content

Commit 862225a

Browse files
committed
PS optimizations.
svn path=/trunk/matplotlib/; revision=944
1 parent 81188fb commit 862225a

File tree

2 files changed

+65
-54
lines changed

2 files changed

+65
-54
lines changed

CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
New entries should be added at the top
22

3+
2005-02-08 Small optimizations in PS backend. They may have a big impact for
4+
large plots, otherwise they don't hurt - FP
5+
36
2005-02-08 Added transparent support for gzipped files in load/save - Fernando
47
Perez (FP from now on).
58

lib/matplotlib/backends/backend_ps.py

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,10 @@ def set_linedash(self, offset, seq):
137137

138138
def set_font(self, fontname, fontsize):
139139
if (fontname,fontsize) != (self.fontname,self.fontsize):
140-
writer = self._pswriter
141-
writer.write("/%s findfont\n"%fontname)
142-
writer.write("%1.3f scalefont\n"%fontsize)
143-
writer.write("setfont\n")
140+
out = ("/%s findfont\n"
141+
"%1.3f scalefont\n"
142+
"setfont\n" % (fontname,fontsize))
143+
self._pswriter.write(out)
144144
self.fontname = fontname
145145
self.fontsize = fontsize
146146

@@ -214,9 +214,10 @@ def _gray(self, im, flipud, rc=0.3, gc=0.59, bc=0.11):
214214
rgbat = im.as_str(flipud)
215215
rgba = fromstring(rgbat[2], UInt8)
216216
rgba.shape = (rgbat[0], rgbat[1], 4)
217-
r = rgba[:,:,0].astype(Float32)
218-
g = rgba[:,:,1].astype(Float32)
219-
b = rgba[:,:,2].astype(Float32)
217+
rgba_f = rgba.astype(Float32)
218+
r = rgba_f[:,:,0]
219+
g = rgba_f[:,:,1]
220+
b = rgba_f[:,:,2]
220221
gray = (r*rc + g*gc + b*bc).astype(UInt8)
221222
return rgbat[0], rgbat[1], gray.tostring()
222223

@@ -283,9 +284,6 @@ def draw_line(self, gc, x0, y0, x1, y1):
283284

284285
def _draw_markers(self, gc, path, x, y, transform):
285286
"""
286-
I'm underscore hiding this method from lines.py right now
287-
since it is incomplete
288-
289287
Draw the markers defined by path at each of the positions in x
290288
and y. path coordinates are points, x and y coords will be
291289
transformed by the transform
@@ -335,7 +333,7 @@ def _draw_lines(self, gc, points):
335333
"""
336334
# inline this for performance
337335
ps = ["%1.3f %1.3f m" % points[0]]
338-
ps.extend(["%1.3f %1.3f l"%point for point in points[1:] ])
336+
ps.extend(["%1.3f %1.3f l" % point for point in points[1:] ])
339337
self._draw_ps("\n".join(ps), gc, None)
340338

341339
def draw_lines(self, gc, x, y):
@@ -345,10 +343,17 @@ def draw_lines(self, gc, x, y):
345343
"""
346344
if debugPS:
347345
self._pswriter.write("% lines\n")
348-
points=zip(x,y)
349-
while points:
350-
self._draw_lines(gc,points[0:1000])
351-
del(points[0:1000])
346+
start = 0
347+
end = 1000
348+
points = zip(x,y)
349+
350+
while 1:
351+
to_draw = points[start:end]
352+
if not to_draw:
353+
break
354+
self._draw_lines(gc,to_draw)
355+
start = end
356+
end += 1000
352357

353358
def draw_point(self, gc, x, y):
354359
"""
@@ -366,11 +371,10 @@ def draw_polygon(self, gc, rgbFace, points):
366371
If rgbFace is not None, fill the poly with it. gc
367372
is a GraphicsContext instance
368373
"""
369-
ps = "%s m\n" % _nums_to_str(*points[0])
370-
for x,y in points[1:]:
371-
ps += "%s l\n" % _nums_to_str(x, y)
372-
ps += "closepath"
373-
self._draw_ps(ps, gc, rgbFace, "polygon")
374+
ps = ["%s m\n" % _nums_to_str(*points[0])]
375+
ps.extend([ "%s l\n" % _nums_to_str(x, y) for x,y in points[1:] ])
376+
ps.append("closepath")
377+
self._draw_ps(''.join(ps), gc, rgbFace, "polygon")
374378

375379
def draw_rectangle(self, gc, rgbFace, x, y, width, height):
376380
"""
@@ -387,27 +391,28 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
387391
"""
388392
draw a Text instance
389393
"""
390-
394+
# local to avoid repeated attribute lookups
395+
write = self._pswriter.write
391396
if ismath:
392397
return self.draw_mathtext(gc, x, y, s, prop, angle)
393398
if debugPS:
394-
self._pswriter.write("% text\n")
399+
write("% text\n")
395400

396401
font = self._get_font(prop)
397402
font.set_text(s,0)
398403

399404
self.set_color(*gc.get_rgb())
400405
self.set_font(font.get_sfnt()[(1,0,0,6)], prop.get_size_in_points())
401-
self._pswriter.write("%s m\n"%_nums_to_str(x,y))
406+
write("%s m\n"%_nums_to_str(x,y))
402407
if angle:
403-
self._pswriter.write("gsave\n")
404-
self._pswriter.write("%s rotate\n"%_num_to_str(angle))
408+
write("gsave\n")
409+
write("%s rotate\n"%_num_to_str(angle))
405410
descent = font.get_descent() / 64.0
406411
if descent:
407-
self._pswriter.write("0 %s rmoveto\n"%_num_to_str(descent))
408-
self._pswriter.write("(%s) show\n"%quote_ps_string(s))
412+
write("0 %s rmoveto\n"%_num_to_str(descent))
413+
write("(%s) show\n"%quote_ps_string(s))
409414
if angle:
410-
self._pswriter.write("grestore\n")
415+
write("grestore\n")
411416

412417
def new_gc(self):
413418
return GraphicsContextPS()
@@ -436,10 +441,11 @@ def _draw_ps(self, ps, gc, rgbFace, command=None):
436441
Emit the PostScript sniplet 'ps' with all the attributes from 'gc'
437442
applied. 'ps' must consist of PostScript commands to construct a path.
438443
"""
439-
# local attr lookup faster and this is
440-
writer = self._pswriter
444+
# local variable eliminates all repeated attribute lookups
445+
write = self._pswriter.write
446+
441447
if debugPS and command:
442-
writer.write("% "+command+"\n")
448+
write("% "+command+"\n")
443449

444450
cliprect = gc.get_clip_rectangle()
445451
self.set_color(*gc.get_rgb())
@@ -453,19 +459,19 @@ def _draw_ps(self, ps, gc, rgbFace, command=None):
453459
self.set_linedash(*gc.get_dashes())
454460
if cliprect:
455461
x,y,w,h=cliprect
456-
writer.write('gsave\n%1.3f %1.3f %1.3f %1.3f clipbox\n' % (w,h,x,y))
462+
write('gsave\n%1.3f %1.3f %1.3f %1.3f clipbox\n' % (w,h,x,y))
457463
# Jochen, is the strip necessary? - this could be a honking big string
458-
writer.write(ps.strip())
459-
writer.write("\n")
464+
write(ps.strip())
465+
write("\n")
460466
if rgbFace:
461467
#print 'rgbface', rgbFace
462-
writer.write("gsave\n")
468+
write("gsave\n")
463469
self.set_color(store=0, *rgbFace)
464-
writer.write("fill\ngrestore\n")
470+
write("fill\ngrestore\n")
465471

466-
writer.write("stroke\n")
472+
write("stroke\n")
467473
if cliprect:
468-
writer.write("grestore\n")
474+
write("grestore\n")
469475

470476

471477
class GraphicsContextPS(GraphicsContextBase):
@@ -491,13 +497,15 @@ def encodeTTFasPS(fontfile):
491497
"""
492498
fontfile = str(fontfile) # TODO: handle unicode filenames
493499
font = file(fontfile, 'rb')
494-
hexdata, data = '', font.read(65520)
495-
while len(data):
496-
hexdata += '<'+'\n'.join([binascii.b2a_hex(data[j:j+36]).upper() \
497-
for j in range(0, len(data), 36)])+'>\n'
500+
hexdata, data = [], font.read(65520)
501+
b2a_hex = binascii.b2a_hex
502+
while data:
503+
hexdata.append('<%s>\n' %
504+
'\n'.join([b2a_hex(data[j:j+36]).upper()
505+
for j in range(0, len(data), 36)]) )
498506
data = font.read(65520)
499-
500-
hexdata = hexdata[:-2] + '00>'
507+
508+
hexdata = ''.join(hexdata)[:-2] + '00>'
501509
font = FT2Font(fontfile)
502510

503511
headtab = font.get_sfnt_table('head')
@@ -525,18 +533,18 @@ def encodeTTFasPS(fontfile):
525533
italicang= '(%d.%d)' % posttab['italicAngle']
526534

527535
numglyphs = font.num_glyphs
528-
glyphs = ''
536+
glyphs = []
529537
for j in range(numglyphs):
530-
glyphs += '/%s %d def' % (font.get_glyph_name(j), j)
538+
glyphs.append('/%s %d def' % (font.get_glyph_name(j), j))
531539
if j != 0 and j%4 == 0:
532-
glyphs += '\n'
540+
glyphs.append('\n')
533541
else:
534-
glyphs += ' '
535-
536-
data = '%%!PS-TrueType-%(version)s-%(revision)s\n' % locals()
542+
glyphs.append(' ')
543+
glyphs = ''.join(glyphs)
544+
data = ['%%!PS-TrueType-%(version)s-%(revision)s\n' % locals()]
537545
if maxmemory:
538-
data += '%%%%VMusage: %(minmemory)d %(maxmemory)d' % locals()
539-
data += """%(dictsize)d dict begin
546+
data.append('%%%%VMusage: %(minmemory)d %(maxmemory)d' % locals())
547+
data.append("""%(dictsize)d dict begin
540548
/FontName /%(fontname)s def
541549
/FontMatrix [1 0 0 1 0 0] def
542550
/FontType 42 def
@@ -558,8 +566,8 @@ def encodeTTFasPS(fontfile):
558566
/CharStrings %(numglyphs)d dict dup begin
559567
%(glyphs)s
560568
end readonly def
561-
FontName currentdict end definefont pop""" % locals()
562-
return data
569+
FontName currentdict end definefont pop""" % locals())
570+
return ''.join(data)
563571

564572

565573
class FigureCanvasPS(FigureCanvasBase):

0 commit comments

Comments
 (0)