Skip to content
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

Cairo text is misaligned vertically #1121

Closed
mdboom opened this issue Aug 20, 2012 · 1 comment
Closed

Cairo text is misaligned vertically #1121

mdboom opened this issue Aug 20, 2012 · 1 comment

Comments

@mdboom
Copy link
Member

mdboom commented Aug 20, 2012

On 19/08/12 23:48, Freddie Witherden wrote:
> Hello,
>
> Using the Cairo backend with the following snippet:
>
> from matplotlib.figure import Figure
> from matplotlib.artist import setp
> from matplotlib.backends.backend_agg import FigureCanvasAgg
> from matplotlib.backends.backend_cairo import FigureCanvasCairo
> import numpy as np
>
> fig = Figure()
> ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8])
> x = np.arange(0, 10, 0.2)
>
> ax1.plot(x, np.sin(x))
> ax1.xaxis.set_ticklabels(['Apr', 'Jul', 'Oct', '\'12', 'Apr', 'Jul'])
> setp(ax1.yaxis.get_ticklabels(), visible=False)
>
> FigureCanvasCairo(fig).print_figure('test.png')
>
>
> Results in the x-axis tick labels being significantly displaced.
> Specifically, "Oct" and "'12" are positioned far closer to the axis than
> either "Apr" or "Jul".
>
> With the AGG backend all of the labels are roughly aligned to the
> baseline of the font -- give or take a pixel.
>
> I have observed this on a Gentoo and Debian system, both running 1.1.1,
> albeit with different default fonts.
>
> Although I am not completely sure it appears as if a label contains a
> glyph that extends below the baseline, e.g. 'p' or 'J', that the label
> is forced away from the axis.
>
> Can anyone suggest a workaround for this (or explain where I am going
> wrong)?

I have been looking into this issue today and it /appears/ to be because
the Cairo backend -- or more precisely -- cairo::show_text method takes
a y-coordinate relative to the baseline.  This makes sense given that
the descent of a font is a well-defined concept in Cairo (and can be
extracted via the font_extents method).  However, as far as I can tell,
matplotlib expects the draw_text method to provide an absolute y-coordinate.

The result is that any text with a descender is pushed downwards
(assuming a default rotation angle).  This can be visualized by

setp(ax1.xaxis.get_ticklabels(), backgroundcolor='r')

The solution is to have the draw_text method account for any descenders.
 After a bit of juggling the relevant portion of draw_text becomes:

           ctx = gc.ctx
           ctx.new_path()
           #ctx.move_to (x, y)
           ctx.select_font_face (prop.get_name(),
                                 self.fontangles [prop.get_style()],
                                 self.fontweights[prop.get_weight()])

           size = prop.get_size_in_points() * self.dpi / 72.0
           ctx.set_font_size(size)

           y_bearing, w, h = ctx.text_extents(s.encode("utf-8"))[1:4]
           ctx.move_to(x, y - (h + y_bearing))

           ctx.save()
           if angle:
              ctx.rotate (-angle * np.pi / 180)
           #ctx.set_font_size (size)
           ctx.show_text (s.encode("utf-8"))
           ctx.restore()

where commented lines highlight modifications (specifically, the
movement of the set_font_size and move_to calls).  In my limited testing
this fixes the aforementioned issues.  Discrepancies between baselines
are now limited to ± 1px (the same as with the AGG backend).
Eliminating these one pixel misalignments is rather difficult so long as
text rendering is performed relative to the bounding box as opposed to a
baseline.

Regards, Freddie.
@mdboom
Copy link
Member Author

mdboom commented Sep 3, 2013

Fixed in 1.3.0

@mdboom mdboom closed this as completed Sep 3, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant