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.

Attachment: signature.asc
Description: OpenPGP digital signature

------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to