Skip to content

Cairo + plot_date = misaligned x-axis labels #1810

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 19, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
11 changes: 11 additions & 0 deletions doc/users/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,17 @@ so that search results are printed prettily:
'ytick.major.size': 4,
'ytick.minor.size': 2})

Better vertical text alignment
------------------------------

The vertical alignment of text is now consistent across backends. You
may see small differences in text placement, particularly with rotated
text.

If you are using a custom backend, note that the `draw_text` renderer
method is now passed the location of the baseline, not the location of
the bottom of the text bounding box.

.. _whats-new-1-2-2:

new in matplotlib 1.2.2
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
the x location of the text in display coords

*y*
the y location of the text in display coords
the y location of the text baseline in display coords

*s*
the text string
Expand All @@ -497,7 +497,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):

if 0: bbox_artist(self, renderer)

to if 1, and then the actual bounding box will be blotted along with
to if 1, and then the actual bounding box will be plotted along with
your text.
"""

Expand Down
12 changes: 9 additions & 3 deletions lib/matplotlib/backends/backend_agg.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,10 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
ox, oy, width, height, descent, font_image, used_characters = \
self.mathtext_parser.parse(s, self.dpi, prop)

x = np.round(x + ox)
y = np.round(y - oy)
xd = descent * np.sin(angle / (180.0 * np.pi))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if np.deg2rad is preferable here... it might even be quicker (untested).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Forgot about that...

yd = descent * np.cos(angle / (180.0 * np.pi))
x = np.round(x + ox - xd)
y = np.round(y - oy + yd)
self._renderer.draw_text_image(font_image, x, y + 1, angle, gc)

def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
Expand All @@ -177,10 +179,14 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
# space) in the following call to draw_text_image).
font.set_text(s, 0, flags=flags)
font.draw_glyphs_to_bitmap(antialiased=rcParams['text.antialiased'])
d = font.get_descent() / 64.0
# The descent needs to be adjusted for the angle
xd = d * np.sin(np.deg2rad(angle))
yd = d * np.cos(np.deg2rad(angle))

#print x, y, int(x), int(y), s
self._renderer.draw_text_image(
font.get_image(), np.round(x), np.round(y) + 1, angle, gc)
font.get_image(), np.round(x - xd), np.round(y + yd) + 1, angle, gc)

def get_text_width_height_descent(self, s, prop, ismath):
"""
Expand Down
18 changes: 7 additions & 11 deletions lib/matplotlib/backends/backend_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1622,15 +1622,15 @@ def draw_gouraud_triangles(self, gc, points, colors, trans):
self.check_gc(gc)
self.file.output(name, Op.shading)

def _setup_textpos(self, x, y, descent, angle, oldx=0, oldy=0, olddescent=0, oldangle=0):
def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0):
if angle == oldangle == 0:
self.file.output(x - oldx, (y + descent) - (oldy + olddescent), Op.textpos)
self.file.output(x - oldx, y - oldy, Op.textpos)
else:
angle = angle / 180.0 * pi
self.file.output( cos(angle), sin(angle),
-sin(angle), cos(angle),
x, y, Op.textmatrix)
self.file.output(0, descent, Op.textpos)
self.file.output(0, 0, Op.textpos)

def draw_mathtext(self, gc, x, y, s, prop, angle):
# TODO: fix positioning and encoding
Expand Down Expand Up @@ -1660,7 +1660,7 @@ def draw_mathtext(self, gc, x, y, s, prop, angle):
fonttype = global_fonttype

if fonttype == 42 or num <= 255:
self._setup_textpos(ox, oy, 0, 0, oldx, oldy)
self._setup_textpos(ox, oy, 0, oldx, oldy)
oldx, oldy = ox, oy
if (fontname, fontsize) != prev_font:
self.file.output(self.file.fontName(fontname), fontsize,
Expand Down Expand Up @@ -1762,7 +1762,7 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None):
self.file.output(elt[1], elt[2], Op.selectfont)
elif elt[0] == 'text':
curx, cury = mytrans.transform((elt[1], elt[2]))
self._setup_textpos(curx, cury, 0, angle, oldx, oldy)
self._setup_textpos(curx, cury, angle, oldx, oldy)
oldx, oldy = curx, cury
if len(elt[3]) == 1:
self.file.output(elt[3][0], Op.show)
Expand Down Expand Up @@ -1811,13 +1811,11 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
if rcParams['pdf.use14corefonts']:
font = self._get_font_afm(prop)
l, b, w, h = font.get_str_bbox(s)
descent = -b * fontsize / 1000
fonttype = 1
else:
font = self._get_font_ttf(prop)
self.track_characters(font, s)
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
descent = font.get_descent() / 64.0

fonttype = rcParams['pdf.fonttype']

Expand Down Expand Up @@ -1857,7 +1855,7 @@ def draw_text_simple():
self.file.fontName(prop),
fontsize,
Op.selectfont)
self._setup_textpos(x, y, descent, angle)
self._setup_textpos(x, y, angle)
self.file.output(self.encode_string(s, fonttype), Op.show, Op.end_text)

def draw_text_woven(chunks):
Expand All @@ -1878,7 +1876,6 @@ def draw_text_woven(chunks):
# output all the 2-byte characters.
for mode in (1, 2):
newx = oldx = 0
olddescent = 0
# Output a 1-byte character chunk
if mode == 1:
self.file.output(Op.begin_text,
Expand All @@ -1888,10 +1885,9 @@ def draw_text_woven(chunks):

for chunk_type, chunk in chunks:
if mode == 1 and chunk_type == 1:
self._setup_textpos(newx, 0, descent, 0, oldx, 0, olddescent, 0)
self._setup_textpos(newx, 0, 0, oldx, 0, 0)
self.file.output(self.encode_string(chunk, fonttype), Op.show)
oldx = newx
olddescent = descent

lastgind = None
for c in chunk:
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_pgf.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
text_args.append("x=%fin" % (x * f))
text_args.append("y=%fin" % (y * f))
text_args.append("left")
text_args.append("bottom")
text_args.append("base")

if angle != 0:
text_args.append("rotate=%f" % angle)
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
#print 'text', s
lines = []
thisx = 0
thisy = font.get_descent() / 64.0
thisy = 0
for c in s:
ccode = ord(c)
gind = cmap.get(ccode)
Expand Down
9 changes: 2 additions & 7 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,8 +852,6 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath, mtext=None):
_glyphs = text2path.get_glyphs_with_font(
font, s, glyph_map=glyph_map, return_new_glyphs_only=True)
glyph_info, glyph_map_new, rects = _glyphs
y -= ((font.get_descent() / 64.0) *
(prop.get_size_in_points() / text2path.FONT_SCALE))

if glyph_map_new:
writer.start(u'defs')
Expand Down Expand Up @@ -953,8 +951,6 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None):
if not ismath:
font = self._get_font(prop)
font.set_text(s, 0.0, flags=LOAD_NO_HINTING)
descent = font.get_descent() / 64.0
y -= descent

fontsize = prop.get_size_in_points()

Expand Down Expand Up @@ -982,10 +978,9 @@ def _draw_text_as_text(self, gc, x, y, s, prop, angle, ismath, mtext=None):
# to the anchor point manually for now.
angle_rad = angle * np.pi / 180.
dir_vert = np.array([np.sin(angle_rad), np.cos(angle_rad)])
y += descent # Undo inappropriate text descent handling
v_offset = np.dot(dir_vert, [(x - ax), (y - ay)])
ax = ax + (v_offset - descent) * dir_vert[0]
ay = ay + (v_offset - descent) * dir_vert[1]
ax = ax + v_offset * dir_vert[0]
ay = ay + v_offset * dir_vert[1]

ha_mpl_to_svg = {'left': 'start', 'right': 'end',
'center': 'middle'}
Expand Down
10 changes: 5 additions & 5 deletions lib/matplotlib/mathtext.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
self.pswriter.write(ps)

def get_results(self, box, used_characters):
ship(0, -self.depth, box)
ship(0, 0, box)
return (self.width,
self.height + self.depth,
self.depth,
Expand All @@ -288,7 +288,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
self.rects.append((x1, self.height - y2, x2 - x1, y2 - y1))

def get_results(self, box, used_characters):
ship(0, -self.depth, box)
ship(0, 0, box)
return (self.width,
self.height + self.depth,
self.depth,
Expand Down Expand Up @@ -316,7 +316,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
(x1, self.height - y1 + 1, x2 - x1, y2 - y1))

def get_results(self, box, used_characters):
ship(0, -self.depth, box)
ship(0, 0, box)
svg_elements = Bunch(svg_glyphs = self.svg_glyphs,
svg_rects = self.svg_rects)
return (self.width,
Expand Down Expand Up @@ -346,7 +346,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
(x1, self.height-y2 , x2 - x1, y2 - y1))

def get_results(self, box, used_characters):
ship(0, -self.depth, box)
ship(0, 0, box)
return (self.width,
self.height + self.depth,
self.depth,
Expand Down Expand Up @@ -374,7 +374,7 @@ def render_rect_filled(self, x1, y1, x2, y2):
(x1, y1 - self.height, x2 - x1, y2 - y1))

def get_results(self, box, used_characters):
ship(0, -self.depth, box)
ship(0, 0, box)
return (self.width,
self.height + self.depth,
self.depth,
Expand Down
8 changes: 4 additions & 4 deletions lib/matplotlib/testing/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def do_test():

yield (do_test,)

def image_comparison(baseline_images=None, extensions=None, tol=10,
def image_comparison(baseline_images=None, extensions=None, tol=13,
freetype_version=None, remove_text=False,
savefig_kwarg=None):
"""
Expand Down Expand Up @@ -260,11 +260,11 @@ def _image_directories(func):
subdir = os.path.splitext(os.path.split(script_name)[1])[0]
else:
mods = module_name.split('.')
mods.pop(0) # <- will be the name of the package being tested (in
mods.pop(0) # <- will be the name of the package being tested (in
# most cases "matplotlib")
assert mods.pop(0) == 'tests'
subdir = os.path.join(*mods)

import imp
def find_dotted_module(module_name, path=None):
"""A version of imp which can handle dots in the module name"""
Expand All @@ -273,7 +273,7 @@ def find_dotted_module(module_name, path=None):
res = _, path, _ = imp.find_module(sub_mod, path)
path = [path]
return res

mod_file = find_dotted_module(func.__module__)[1]
basedir = os.path.dirname(mod_file)

Expand Down
Binary file modified lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified lib/matplotlib/tests/baseline_images/test_axes/const_xy.pdf
Binary file not shown.
Binary file modified lib/matplotlib/tests/baseline_images/test_axes/const_xy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading