You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
The text was updated successfully, but these errors were encountered:
The text was updated successfully, but these errors were encountered: