Skip to content

Commit 615fe7a

Browse files
committed
Add valignment = 'baseline' feature to align text by its baseline.
svn path=/trunk/matplotlib/; revision=3760
1 parent 80321a3 commit 615fe7a

13 files changed

Lines changed: 126 additions & 251 deletions

‎lib/matplotlib/afm.py‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ def string_width_height(self, s):
334334

335335
return totalw, maxy-miny
336336

337-
def get_str_bbox(self, s):
337+
def get_str_bbox_and_descent(self, s):
338338
"""
339339
Return the string bounding box
340340
"""
@@ -369,9 +369,15 @@ def get_str_bbox(self, s):
369369
thismin = b
370370
if thismin<miny: miny = thismin
371371

372-
return left, miny, totalw, maxy-miny
372+
return left, miny, totalw, maxy-miny, -miny
373373

374374

375+
def get_str_bbox(self, s):
376+
"""
377+
Return the string bounding box
378+
"""
379+
return self.get_str_bbox_and_descent(s)[:4]
380+
375381
def get_name_char(self, c):
376382
"""
377383
Get the name of the character, ie, ';' is 'semicolon'

‎lib/matplotlib/backend_bases.py‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,12 +421,13 @@ def get_text_extent(self, text): # is not used, can be removed?
421421
"""
422422
return transforms.lbwh_to_bbox(0,0,1,1) # your values here
423423

424-
def get_text_width_height(self, s, prop, ismath):
424+
def get_text_width_height_descent(self, s, prop, ismath):
425425
"""
426-
get the width and height in display coords of the string s
427-
with FontPropertry prop
426+
get the width and height, and the offset from the bottom to the
427+
baseline (descent), in display coords of the string s with
428+
FontPropertry prop
428429
"""
429-
return 1,1
430+
return 1,1,1
430431

431432
def new_gc(self):
432433
"""

‎lib/matplotlib/backends/backend_agg.py‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
172172
"""
173173
if __debug__: verbose.report('RendererAgg.draw_mathtext',
174174
'debug-annoying')
175-
ox, oy, width, height, fonts, used_characters = \
175+
ox, oy, width, height, descent, fonts, used_characters = \
176176
self.mathtext_parser.parse(s, self.dpi.get(), prop)
177177

178178
if angle == 90:
@@ -186,7 +186,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
186186
for font in fonts:
187187
if angle == 90:
188188
font.horiz_image_to_vert_image() # <-- Rotate
189-
self._renderer.draw_text( font, x, y, gc)
189+
self._renderer.draw_text( font, x, y + 1, gc)
190190
if 0:
191191
self._renderer.draw_rectangle(gc, None,
192192
int(x),
@@ -212,10 +212,10 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
212212

213213
#print x, y, int(x), int(y)
214214

215-
self._renderer.draw_text(font, int(x), int(y), gc)
215+
self._renderer.draw_text(font, int(x), int(y) + 1, gc)
216216

217217

218-
def get_text_width_height(self, s, prop, ismath, rgb=(0,0,0)):
218+
def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)):
219219
"""
220220
get the width and height in display coords of the string s
221221
with FontPropertry prop
@@ -233,15 +233,17 @@ def get_text_width_height(self, s, prop, ismath, rgb=(0,0,0)):
233233
return n,m
234234

235235
if ismath:
236-
ox, oy, width, height, fonts, used_characters = \
236+
ox, oy, width, height, descent, fonts, used_characters = \
237237
self.mathtext_parser.parse(s, self.dpi.get(), prop)
238-
return width, height
238+
return width, height, depth
239239
font = self._get_agg_font(prop)
240240
font.set_text(s, 0.0, flags=LOAD_DEFAULT) # the width and height of unrotated string
241241
w, h = font.get_width_height()
242+
d = font.get_descent()
242243
w /= 64.0 # convert from subpixels
243244
h /= 64.0
244-
return w, h
245+
d /= 64.0
246+
return w, h, d
245247

246248
def draw_tex(self, gc, x, y, s, prop, angle):
247249
# todo, handle props, angle, origins
@@ -250,7 +252,7 @@ def draw_tex(self, gc, x, y, s, prop, angle):
250252
dpi = self.dpi.get()
251253

252254
flip = angle==90
253-
w,h = self.get_text_width_height(s, prop, 'TeX', rgb)
255+
w,h,d = self.get_text_width_height_descent(s, prop, 'TeX', rgb)
254256
if flip:
255257
w,h = h,w
256258
x -= w

‎lib/matplotlib/backends/backend_cairo.py‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle):
304304
if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name())
305305

306306
ctx = gc.ctx
307-
width, height, glyphs, rects = self.mathtext_parser.parse(
307+
width, height, descent, glyphs, rects = self.mathtext_parser.parse(
308308
s, self.dpi.get(), prop)
309309

310310
ctx.save()
@@ -349,12 +349,12 @@ def get_canvas_width_height(self):
349349
return self.width, self.height
350350

351351

352-
def get_text_width_height(self, s, prop, ismath):
352+
def get_text_width_height_descent(self, s, prop, ismath):
353353
if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name())
354354
if ismath:
355-
width, height, fonts, used_characters = self.mathtext_parser.parse(
355+
width, height, descent, fonts, used_characters = self.mathtext_parser.parse(
356356
s, self.dpi.get(), prop)
357-
return width, height
357+
return width, height, descent
358358

359359
ctx = self.text_ctx
360360
ctx.save()
@@ -373,10 +373,10 @@ def get_text_width_height(self, s, prop, ismath):
373373
# save/restore prevents the problem
374374
ctx.set_font_size (size)
375375

376-
w, h = ctx.text_extents (s)[2:4]
376+
y_bearing, w, h = ctx.text_extents (s)[1:4]
377377
ctx.restore()
378378

379-
return w, h
379+
return w, h, h + y_bearing
380380

381381

382382
def new_gc(self):

‎lib/matplotlib/backends/backend_gd.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def get_canvas_width_height(self):
5959
'return the canvas width and height in display coords'
6060
return self.width, self.height
6161

62-
def get_text_width_height(self, s, prop, ismath):
62+
def get_text_width_height_descent(self, s, prop, ismath):
6363
"""
6464
get the width and height in display coords of the string s
6565
with fontsize in points
@@ -78,7 +78,7 @@ def get_text_width_height(self, s, prop, ismath):
7878

7979
w = abs(lrx - llx)
8080
h = abs(lly - uly)
81-
return w, h
81+
return w, h, h
8282

8383

8484
def flipy(self):

‎lib/matplotlib/backends/backend_gdk.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
199199

200200

201201
def _draw_mathtext(self, gc, x, y, s, prop, angle):
202-
width, height, fonts, used_characters = self.mathtext_parser.parse(
202+
width, height, descent, fonts, used_characters = self.mathtext_parser.parse(
203203
s, self.dpi.get(), prop)
204204

205205
if angle==90:
@@ -340,15 +340,15 @@ def flipy(self):
340340
def get_canvas_width_height(self):
341341
return self.width, self.height
342342

343-
def get_text_width_height(self, s, prop, ismath):
343+
def get_text_width_height_descent(self, s, prop, ismath):
344344
if ismath:
345-
width, height, fonts, used_characters = self.mathtext_parser.parse(
345+
width, height, descent, fonts, used_characters = self.mathtext_parser.parse(
346346
s, self.dpi.get(), prop)
347-
return width, height
347+
return width, height, descent
348348

349349
layout, inkRect, logicalRect = self._get_pango_layout(s, prop)
350350
l, b, w, h = inkRect
351-
return w, h+1
351+
return w, h+1, h + 1
352352

353353
def new_gc(self):
354354
return GraphicsContextGDK(renderer=self)

‎lib/matplotlib/backends/backend_pdf.py‎

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,7 @@ def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0):
12241224

12251225
def draw_mathtext(self, gc, x, y, s, prop, angle):
12261226
# TODO: fix positioning and encoding
1227-
width, height, glyphs, rects, used_characters = \
1227+
width, height, descent, glyphs, rects, used_characters = \
12281228
self.mathtext_parser.parse(s, 72, prop)
12291229
self.merge_used_characters(used_characters)
12301230

@@ -1465,30 +1465,27 @@ def draw_text_woven(chunks):
14651465
else:
14661466
return draw_text_woven(chunks)
14671467

1468-
def get_text_width_height(self, s, prop, ismath):
1469-
# FT2Font can handle unicode, and so can we
1470-
# if isinstance(s, unicode):
1471-
# s = s.encode('cp1252', 'replace')
1472-
1468+
def get_text_width_height_descent(self, s, prop, ismath):
14731469
if ismath:
1474-
w, h, glyphs, rects, used_characters = \
1470+
w, h, d, glyphs, rects, used_characters = \
14751471
self.mathtext_parser.parse(s, 72, prop)
14761472

14771473
elif rcParams['pdf.use14corefonts']:
14781474
font = self._get_font_afm(prop)
1479-
l, b, w, h = font.get_str_bbox(s)
1480-
fontsize = prop.get_size_in_points()
1481-
w *= fontsize / 1000
1482-
h *= fontsize / 1000
1483-
1475+
l, b, w, h, d = font.get_str_bbox_and_descent(s)
1476+
scale = prop.get_size_in_points() / 1000.0
1477+
w *= scale
1478+
h *= scale
1479+
d *= scale
14841480
else:
14851481
font = self._get_font_ttf(prop)
14861482
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
14871483
w, h = font.get_width_height()
14881484
w /= 64.0
14891485
h /= 64.0
1490-
1491-
return w, h
1486+
d = font.get_descent()
1487+
d /= 64.0
1488+
return w, h, d
14921489

14931490
def _get_font_afm(self, prop):
14941491
key = hash(prop)

‎lib/matplotlib/backends/backend_ps.py‎

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ def get_canvas_width_height(self):
263263
'return the canvas width and height in display coords'
264264
return self.width, self.height
265265

266-
def get_text_width_height(self, s, prop, ismath):
266+
def get_text_width_height_descent(self, s, prop, ismath):
267267
"""
268268
get the width and height in display coords of the string s
269269
with FontPropertry prop
@@ -276,30 +276,36 @@ def get_text_width_height(self, s, prop, ismath):
276276
w = (r-l)
277277
h = (t-b)
278278
#print s, w, h
279-
return w, h
279+
# TODO: We need a way to get a good baseline from
280+
# text.usetex
281+
return w, h, h
280282

281283
if ismath:
282-
width, height, pswriter, used_characters = \
284+
width, height, descent, pswriter, used_characters = \
283285
self.mathtext_parser.parse(s, 72, prop)
284-
return width, height
286+
return width, height, descent
285287

286288
if rcParams['ps.useafm']:
287289
if ismath: s = s[1:-1]
288290
font = self._get_font_afm(prop)
289-
l,b,w,h = font.get_str_bbox(s)
291+
l,b,w,h,d = font.get_str_bbox_and_descent(s)
290292

291293
fontsize = prop.get_size_in_points()
292-
w *= 0.001*fontsize
293-
h *= 0.001*fontsize
294-
return w, h
294+
scale = 0.001*fontsize
295+
w *= scale
296+
h *= scale
297+
d *= scale
298+
return w, h, d
295299

296300
font = self._get_font_ttf(prop)
297301
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
298302
w, h = font.get_width_height()
299303
w /= 64.0 # convert from subpixels
300304
h /= 64.0
305+
d = font.get_descent()
306+
d /= 64.0
301307
#print s, w, h
302-
return w, h
308+
return w, h, d
303309

304310
def flipy(self):
305311
'return true if small y numbers are top for renderer'
@@ -661,7 +667,7 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'):
661667
"""
662668
draw a Text instance
663669
"""
664-
w, h = self.get_text_width_height(s, prop, ismath)
670+
w, h, bl = self.get_text_width_height_baseline(s, prop, ismath)
665671
fontsize = prop.get_size_in_points()
666672
corr = 0#w/2*(fontsize-10)/10
667673
pos = _nums_to_str(x-corr, y)
@@ -857,7 +863,7 @@ def draw_mathtext(self, gc,
857863
if debugPS:
858864
self._pswriter.write("% mathtext\n")
859865

860-
width, height, pswriter, used_characters = \
866+
width, height, descent, pswriter, used_characters = \
861867
self.mathtext_parser.parse(s, 72, prop)
862868
self.merge_used_characters(used_characters)
863869
self.set_color(*gc.get_rgb())

‎lib/matplotlib/backends/backend_svg.py‎

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ def draw_polygon(self, gc, rgbFace, points):
232232

233233
def draw_rectangle(self, gc, rgbFace, x, y, width, height):
234234
details = 'width="%f" height="%f" x="%f" y="%f"' % (width, height, x,
235-
self.height-y-height)
235+
self.height-y-height)
236236
self._draw_svg_element('rect', details, gc, rgbFace)
237237

238238
def draw_text(self, gc, x, y, s, prop, angle, ismath):
@@ -241,7 +241,9 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
241241
return
242242

243243
font = self._get_font(prop)
244-
244+
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
245+
y -= font.get_descent() / 64.0
246+
245247
thetext = escape_xml_text(s)
246248
fontfamily = font.family_name
247249
fontstyle = font.style_name
@@ -277,7 +279,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath):
277279
currx += kern/64.0
278280

279281
svg.append('<use xlink:href="#%s" transform="translate(%s)"/>\n'
280-
% (charid, currx))
282+
% (charid, currx * (self.FONT_SCALE / fontsize)))
281283

282284
currx += (glyph.linearHoriAdvance / 65536.0)
283285
svg.append('</g>\n')
@@ -338,7 +340,7 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle):
338340
"""
339341
Draw math text using matplotlib.mathtext
340342
"""
341-
width, height, svg_elements, used_characters = \
343+
width, height, descent, svg_elements, used_characters = \
342344
self.mathtext_parser.parse(s, 72, prop)
343345
svg_glyphs = svg_elements.svg_glyphs
344346
svg_rects = svg_elements.svg_rects
@@ -426,17 +428,19 @@ def flipy(self):
426428
def get_canvas_width_height(self):
427429
return self.width, self.height
428430

429-
def get_text_width_height(self, s, prop, ismath):
431+
def get_text_width_height_descent(self, s, prop, ismath):
430432
if ismath:
431-
width, height, trash, used_characters = \
433+
width, height, descent, trash, used_characters = \
432434
self.mathtext_parser.parse(s, 72, prop)
433-
return width, height
435+
return width, height, descent
434436
font = self._get_font(prop)
435437
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
436438
w, h = font.get_width_height()
437439
w /= 64.0 # convert from subpixels
438440
h /= 64.0
439-
return w, h
441+
d = font.get_descent()
442+
d /= 64.0
443+
return w, h, d
440444

441445

442446
class FigureCanvasSVG(FigureCanvasBase):

‎lib/matplotlib/backends/backend_template.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ def flipy(self):
9393
def get_canvas_width_height(self):
9494
return 100, 100
9595

96-
def get_text_width_height(self, s, prop, ismath):
97-
return 1, 1
96+
def get_text_width_height_descent(self, s, prop, ismath):
97+
return 1, 1, 1
9898

9999
def new_gc(self):
100100
return GraphicsContextTemplate()

0 commit comments

Comments
 (0)