Hello, AFAIK, current backends (I only tested agg, pdf, and ps) do not properly respect the text baseline when text is rendered using TeX. The get_text_width_height_descent() method in Agg and PS backends simply return 0 for the descent value. While PDF backend uses the dviread module to figure out correct descent values, there are cases this does not work well (e.g. $\frac{1}{2}\pi$).
As an example, the attached figure shows the result for the Agg backend. In all cases, the texts are placed at (0,0) with baseline-alignment. Leftmost one is when usetex=False, which has a correct baseline. The middle one is when usetex=True. It is bottom aligned, which is not intended. The rightmost one is also when usetex=True but after the patch I describe below. First of all, I borrowed this idea from the PyX which is in GPL. Although there is little of copying, other than the basic idea, I'm not 100% sure if this could be BSD-compatible. Anyhow, the idea is that you can have LateX to print out the width, height, and descent (=depth) of a given text by enclosing the text in a box. For example, \newbox\MatplotlibBox% \setbox\MatplotlibBox=\hbox{$\frac{1}{2}\pi$}% \copy\MatplotlibBox \immediate\write16{MatplotlibBox:\the\wd\MatplotlibBox,\the\ht\MatplotlibBox,\the\dp\MatplotlibBox}% I define a newbox (called MatplotlibBox) which encloses $\frac{1}{2}\pi$. And then print out the width, height and depth of the box. Attached is a patch of a texmanager.py which utilize above method to figure out the dimension of the text. The template string to generate a ".tex" file is slightly modified. After latex is run, the dimensional information of the text is extracted and saved in ".baseline" file and get_text_width_height_descent() method is added under the TexManager class, which reads in the ".baseline" file and return its content. (you need to empty out the tex.cache directory for this work correctly). A backend can simply call the get_text_width_height_descent() of texmanager (a simple patch for the Agg backend is attached). I also tested this with PS and PDF backends and they worked out fine. So if the license issue is okay, I wonder if this patch can be reviewed and applied (after any necessary modifications) to improve the baseline handling in matploltib. Regards, -JJ
<<attachment: test_baseline_comparison.png>>
Index: lib/matplotlib/texmanager.py =================================================================== --- lib/matplotlib/texmanager.py (revision 6055) +++ lib/matplotlib/texmanager.py (working copy) @@ -236,6 +236,12 @@ else: unicode_preamble = '' + + + # newbox, setbox, immediate, etc. are used to find the box + # extent of the rendered text. + + s = r"""\documentclass{article} %s %s @@ -243,7 +249,10 @@ \usepackage[papersize={72in,72in}, body={70in,70in}, margin={1in,1in}]{geometry} \pagestyle{empty} \begin{document} -\fontsize{%f}{%f}%s +\newbox\MatplotlibBox%% +\setbox\MatplotlibBox=\hbox{{\fontsize{%f}{%f}%s}}%% +\copy\MatplotlibBox +\immediate\write16{MatplotlibBox:\the\wd\MatplotlibBox,\the\ht\MatplotlibBox,\the\dp\MatplotlibBox}%% \end{document} """ % (self._font_preamble, unicode_preamble, custom_preamble, fontsize, fontsize*1.25, tex) @@ -283,6 +292,14 @@ fh = file(outfile) report = fh.read() fh.close() + + # find the box extent information in the latex output + # file and save them in basefile+".baseline" file + si = report.find("MatplotlibBox:") + ssi = si + len("MatplotlibBox:") + ei = report.find("\n", ssi) + open(basefile+'.baseline',"w").write(report[ssi:ei]) + except IOError: report = 'No latex error report available.' if exit_status: @@ -292,6 +309,7 @@ for fname in glob.glob(basefile+'*'): if fname.endswith('dvi'): pass elif fname.endswith('tex'): pass + elif fname.endswith('baseline'): pass else: try: os.remove(fname) except OSError: pass @@ -441,3 +459,22 @@ self.rgba_arrayd[key] = Z return Z + + + def get_text_width_height_descent(self, tex, fontsize): + """ + return text size in point + """ + basefile = self.get_basefile(tex, fontsize) + baselinefile = '%s.baseline'% basefile + + + if DEBUG or not os.path.exists(baselinefile): + dvifile = self.make_dvi(tex, fontsize) + + # width, height, depth of the bpx + # depth = descent, and height does not include depth + l = open(baselinefile).read().split(",") + width, height, depth = [float(l1[:-2]) for l1 in l] # get rid of "pt" + + return width, height+depth, depth
Index: lib/matplotlib/backends/backend_agg.py =================================================================== --- lib/matplotlib/backends/backend_agg.py (revision 6055) +++ lib/matplotlib/backends/backend_agg.py (working copy) @@ -121,15 +121,16 @@ # texmanager more efficient. It is not meant to be used # outside the backend """ + + if ismath=='TeX': - # todo: handle props - size = prop.get_size_in_points() texmanager = self.get_texmanager() - Z = texmanager.get_grey(s, size, self.dpi) - m,n = Z.shape - # TODO: descent of TeX text (I am imitating backend_ps here -JKS) - return n, m, 0 + fontsize = prop.get_size_in_points() /72.*self.dpi + w, h, d = texmanager.get_text_width_height_descent(s, fontsize) + return w, h, d + + if ismath: ox, oy, width, height, descent, fonts, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop)
------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel